home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Sample Code / Text / SimpleText Sample / GXFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-17  |  94.8 KB  |  3,184 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        GXFile.c
  3.  
  4.     Contains:    GX print file support for simple text application.
  5.  
  6.     Version:    SimpleText 1.4 or later
  7.  
  8. ** Copyright 1993-1996 Apple Computer. All rights reserved.
  9. **
  10. **    You may incorporate this sample code into your applications without
  11. **    restriction, though the sample code has been provided "AS IS" and the
  12. **    responsibility for its operation is 100% yours.  However, what you are
  13. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  14. **    after having made changes. If you're going to re-distribute the source,
  15. **    we require that you make it clear in the source that the code was
  16. **    descended from Apple Sample Code, but that you've made changes.
  17.  
  18. */
  19.  
  20. #include "MacIncludes.h"
  21.  
  22. #include "GXFile.h"
  23.  
  24. #pragma segment GXFile
  25.  
  26. // --------------------------------------------------------------------------------------------------------------
  27. // PRIVATE TYPEDEFS AND DECLARES
  28. // --------------------------------------------------------------------------------------------------------------
  29. // items to the left of the horizontal scroll bar
  30. #define kScrollAreaWidth    120
  31. #define kPageControlsWidth    32
  32. #define kZoomControlsWidth    26
  33. #define kToolControlWidth    16
  34.  
  35. // items in the pop up page selection window
  36. #define kPageSliderHeight    10
  37. #define kPageSliderMargins    7
  38. #define kPageThumbEdge        4
  39. #define kPageThumbHeight    (kPageSliderHeight + kPageThumbEdge*2)
  40. #define kPageThumbWidth        (kPageThumbHeight / 2)
  41. #define kPageThumbMargins    3
  42. #define kProxyHeight        150
  43. #define kProxyWidth            150
  44. #define kPopUpWindowHeightSmall    (kPageThumbHeight + kPageSliderMargins*2 + kPageThumbEdge*2)
  45. #define kPopUpWindowHeightLarge    (kPageThumbHeight + kPageSliderMargins*3 + kPageThumbEdge*2 + kProxyHeight)
  46.  
  47. #define kMinGXDocSize        kMinDocSize
  48.  
  49. // PICT proxies for the pages
  50. #define kProxyBaseID        (gxPrintingTagID)
  51. #define kProxyType            'prxy'
  52.  
  53. // flattened GX shapes for annotations
  54. #define kAnnotationBaseID    (gxPrintingTagID)
  55. #define kAnnotationType        'anot'
  56.  
  57. // table of pop up menu items and corosponding zoom factors
  58. typedef struct
  59.     {
  60.     short    menuItem;
  61.     Fixed    zoomFactor;
  62.     } ZoomTableEntry;
  63.     
  64. typedef struct
  65.     {
  66.     short    theFont;
  67.     short    theSize;
  68.     } TextState;
  69.     
  70. typedef struct  
  71.     {
  72.     gxSpoolBlock    spool;
  73.     long            reference;
  74.     long            position;
  75.     long            size;
  76.     void            *data;
  77.     void            *userField;
  78.     } userSpool;
  79.  
  80. #define LONGALIGN(n)        (((n) + 3) & ~3L)
  81. #define kAtomHeaderSize        (sizeof(Size) + sizeof(OSType))
  82. #define ABS(n)                (((n) < 0) ? -(n) : (n))
  83.  
  84. #if GENERATINGCFM
  85.     extern pascal OSErr SetImageDescriptionExtension(ImageDescriptionHandle desc, Handle extension, long idType);
  86. #endif
  87.  
  88. // --------------------------------------------------------------------------------------------------------------
  89. // FORWARD DECLARES
  90. // --------------------------------------------------------------------------------------------------------------
  91. OSErr    GXGetDocumentRect(WindowRef pWindow, WindowDataPtr pData, 
  92.             LongRect * documentRectangle, Boolean forGrow);
  93. OSErr    GXCommand(WindowRef pWindow, WindowDataPtr pData, short commandID, long menuResult);
  94.  
  95. // --------------------------------------------------------------------------------------------------------------
  96. // LOCAL GLOBALS
  97. // --------------------------------------------------------------------------------------------------------------
  98. static ZoomTableEntry gZoomTable[] = {
  99.                                 {i50,     0x8000},
  100.                                 {i100,    ff(1)},
  101.                                 {i112,    0x00011EB8},
  102.                                 {i150,     0x00018000},
  103.                                 {i200,    ff(2)},
  104.                                 {i400,    ff(4)},
  105.                                 {0,0}};
  106.  
  107.  
  108. // --------------------------------------------------------------------------------------------------------------
  109. // PRIVATE ROUTINES
  110. // --------------------------------------------------------------------------------------------------------------
  111.  
  112. static void GetCurrentPageAndPaper(WindowDataPtr pData, gxRectangle *pPageSize, gxRectangle *pPaperSize)
  113. {
  114.     GXGetFormatDimensions( ((GXDataPtr)pData)->currentPageFormat, pPageSize, pPaperSize);    
  115.     if (((GXDataPtr)pData)->dontShowMargins)
  116.         *pPaperSize = *pPageSize;
  117.         
  118. } // GetCurrentPageAndPaper
  119.  
  120. // ------------------------------------------------------------------------------------------------------
  121. static void InitColorMatrix(Fixed m[5][4])
  122. {
  123.     register Fixed *x;
  124.     register short i;
  125.  
  126.     x = &m[0][0];
  127.     for(i = 19; i>=0; i--)
  128.         *x++ = 0;
  129.     m[0][0] = m[1][1] = m[2][2] = m[3][3] = fixed1;           /* Identity matrix, for cleanliness */
  130.     
  131. } // InitColorMatrix
  132.  
  133. // --------------------------------------------------------------------------------------------------------------
  134. static void RectangleToRect(const gxRectangle* gxr, Rect* qdr)
  135. {
  136.     qdr->left = FixedRound(gxr->left);
  137.     qdr->top = FixedRound(gxr->top);
  138.     qdr->right = FixedRound(gxr->right);
  139.     qdr->bottom = FixedRound(gxr->bottom);
  140.     
  141. } // RectangleToRect
  142.  
  143. // --------------------------------------------------------------------------------------------------------------
  144. #define allocationIncrement   1024     /* the storage handle is grown by this amount */
  145.  
  146. static long HandleSpoolProc(gxSpoolCommand command,  userSpool *block)
  147. {
  148.     gxGraphicsError    anErr = noErr;
  149.     
  150.        switch (command)
  151.            {
  152.           case gxOpenReadSpool:
  153.              block->size = 0;
  154.              block->position = 0;
  155.               break;
  156.       
  157.           case gxOpenWriteSpool:
  158.              block->data = NewHandle(allocationIncrement);
  159.              block->size = allocationIncrement;
  160.              block->position = 0;
  161.             anErr = MemError();
  162.               break;
  163.       
  164.           case gxReadSpool:
  165.              BlockMoveData((*(char **) block->data) + block->position, block->spool.buffer, block->spool.count);
  166.              block->position += block->spool.count;
  167.               break;
  168.  
  169.           case gxWriteSpool:
  170.               {  
  171.             register long oldPosition;
  172.  
  173.             oldPosition = block->position;
  174.             block->position += block->spool.count;
  175.  
  176.             /* make sure there is at least enough room for one buffer size past current pointer */
  177.             if (block->position + block->spool.bufferSize > block->size)      
  178.                  {
  179.                 block->size += block->spool.bufferSize;
  180.                 HUnlock((Handle) block->data);
  181.                 SetHandleSize((Handle) block->data, block->size);
  182.                 anErr = MemError();
  183.                 HLock((Handle) block->data);
  184.                  }
  185.             if (anErr == noErr)
  186.                  BlockMoveData(block->spool.buffer, (*(char **) block->data + oldPosition), block->spool.count);
  187.               }
  188.               break;
  189.       
  190.           case gxCloseSpool:
  191.              SetHandleSize((Handle) block->data, block->position);
  192.               break;
  193.            }
  194.         
  195.    return anErr;
  196.    
  197. } // HandleSpoolProc
  198.  
  199. #if GENERATINGCFM
  200.     static RoutineDescriptor gHandleSpoolProcRD = BUILD_ROUTINE_DESCRIPTOR(uppgxSpoolProcInfo, HandleSpoolProc);
  201.     static gxSpoolUPP gHandleSpoolProc = &gHandleSpoolProcRD;
  202. #else
  203.     static gxSpoolUPP gHandleSpoolProc = NewgxSpoolProc(HandleSpoolProc);
  204. #endif
  205.  
  206. // --------------------------------------------------------------------------------------------------------------
  207. static long* AppendAtom(long stream[], Size size, OSType tag, const void* data)
  208. {
  209.  
  210.     *stream++    = size + kAtomHeaderSize;
  211.     *stream++    = tag;
  212.     BlockMoveData(data, (Ptr)stream, size);
  213.  
  214.     return (long*)((char*)stream + size);
  215.     
  216. } // AppendAtom
  217.  
  218. // --------------------------------------------------------------------------------------------------------------
  219. static Handle CreateQDGXStream(gxShape source, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground)
  220. /*
  221.  *    See the comment on DecompressShape for an explaination of the parameters.
  222.  *    This routine is used by both DecompressShape for embedding shapes in PICTs,
  223.  *    and AddQDGXRecorderFrame for making gx movies.
  224. */
  225. {
  226.     #define            gxForPrintingOnlyAtom    'fpto'
  227.     #define            gxEraseBackgroundAtom    'erbg'
  228.  
  229.     long            atomCount, shapeSize, proxieSize, dataSize, fontListSize;
  230.     Handle            dataHdl, shapeHdl;
  231.     gxFlatFontList*    fontList;
  232.     gxTag            fontListTag;
  233.       userSpool         block;
  234.  
  235.     block.spool.spoolProcedure = gHandleSpoolProc;
  236.     block.spool.buffer = nil;
  237.     block.spool.bufferSize = 0;
  238.     GXFlattenShape(source, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool);
  239.     shapeHdl = (Handle) block.data;
  240.     if (shapeHdl == nil)
  241.         return nil;
  242.  
  243.     if (proxie)
  244.         {    
  245.         atomCount = 2;
  246.         proxieSize = LONGALIGN(GetHandleSize((Handle)proxie));
  247.         }
  248.     else
  249.         {    
  250.         atomCount = 1;
  251.         proxieSize = 0;
  252.         }
  253.     shapeSize = LONGALIGN(GetHandleSize(shapeHdl));
  254.  
  255.     if (forPrintingOnly)
  256.         ++atomCount;
  257.     if (eraseBackground)
  258.         ++atomCount;
  259.  
  260.     fontListSize = 0;
  261.     fontList = nil;
  262.     GXIgnoreGraphicsWarning(count_out_of_range);
  263.     if (GXGetShapeTags(source, gxFlatFontListItemTag, 1, 1, &fontListTag) > 0)
  264.         {    
  265.         fontListSize = GXGetTag(fontListTag, nil, nil);
  266.         if (fontListSize > 0)
  267.             {    
  268.             fontList = (gxFlatFontList*)NewPtr(fontListSize);
  269.             if (fontList != nil)
  270.                 {    
  271.                 GXGetTag(fontListTag, nil, fontList);
  272.                 fontListSize = LONGALIGN(fontListSize);
  273.                 ++atomCount;
  274.                 }
  275.             else
  276.                 fontListSize = 0;
  277.             }
  278.         }
  279.     GXPopGraphicsWarning();        // count_out_of_range
  280.  
  281.     dataSize = atomCount * kAtomHeaderSize + shapeSize + proxieSize + fontListSize + sizeof(long);
  282.     dataHdl = NewHandle(dataSize);
  283.     if (dataHdl == nil)
  284.         {    
  285.         DisposeHandle(shapeHdl);
  286.         if (fontList)
  287.             DisposePtr((Ptr)fontList);
  288.         return nil;
  289.         }
  290.     
  291.     {    
  292.         long* p = (long*)*dataHdl;
  293.  
  294.         if (forPrintingOnly)
  295.             p = AppendAtom(p, 0, gxForPrintingOnlyAtom, nil);
  296.         if (eraseBackground)
  297.             p = AppendAtom(p, 0, gxEraseBackgroundAtom, nil);
  298.         if (proxie)
  299.             p = AppendAtom(p, proxieSize, 'PICT', *proxie);
  300.         if (fontList)
  301.             p = AppendAtom(p, fontListSize, gxFlatFontListItemTag, fontList);
  302.         p = AppendAtom(p, shapeSize, 'qdgx', *shapeHdl);
  303.         *p++ = 0;        // end of the atom-list
  304.  
  305.         DisposeHandle(shapeHdl);
  306.         if (fontList)
  307.             DisposePtr((Ptr)fontList);
  308.     }
  309.     return dataHdl;
  310.  
  311. } // CreateQDGXStream
  312.  
  313. // --------------------------------------------------------------------------------------------------------------
  314. static PicHandle DecompressShape(gxShape theShape, PicHandle proxie, Boolean forPrintingOnly, Boolean eraseBackground)
  315. /*
  316.  *    This guy returns a Quickdraw picture containing an embedded shape, and a proxie
  317.  *    of the shape, if proxie is not nil. This is called by ShapeToScrap and DragAndDropShape.
  318.  *
  319.  *    theShape            • the shape you want to embedd in a PICT
  320.  *    proxie            • a PICT to be drawn if theShape cannot be drawn (optional but recommended)
  321.  *    forPrintingOnly        • if TRUE, then the decompressor will always look for the proxie
  322.  *                    and theShape will only be used when printing. Use this setting if
  323.  *                    theShape might be too large or too slow when drawn from other apps.
  324.  *                    • If FALSE, then the decompressor will draw theShape unless it
  325.  *                    gets an error, in which case it will look for a proxie.
  326.  *    eraseBackground    • if TRUE, the decompressor will always erase the background to WHITE
  327.  *                    before drawing the shape. This is slower, but needed if the shape does not
  328.  *                    fill its bounding rectangle.
  329.  *                    • if FALSE, the decompressor will just draw the shape. Use this setting
  330.  *                    if the shape entirely fills its bounding rectangle.
  331.  *
  332.  *    The shape [and proxie] is embedded by constructing a stream of atoms. Each atom begins
  333.  *    with a size (long) and a type (OSType) and then the data for that type. After the last atom,
  334.  *    there is a trailing zero (long) to mark the end of the stream. For embedded shapes, the type
  335.  *    is 'qdgx', and for the proxie the type is 'PICT'. Note that the size fields are rounded up to
  336.  *    a multiple of 4. Finally, to alert QuickTime that the data is in this parsable form with a
  337.  *    possible PICT proxie, we add a 'prxy' extension to the ImageDescriptionHandle.
  338.  *
  339.  *    Picture of this form will draw the embedded shape when an application calls DrawPicture
  340.  *    if GX is around, and if not, the proxie will be drawn. When printed, the shape or the proxie
  341.  *    will be printed. This is meant to replace the PicComment described in GX 1.0 for embedding
  342.  *    shapes in pictures.
  343.  *
  344.  *    If you want to include a flatFontList tag, be sure that theShape is a picture, otherwise GX will
  345.  *    not return the tag after GXFlattenShape. The flatFontList tag makes certain printing conditions
  346.  *    more efficient (i.e. font downloading to postscript printers).
  347.  *
  348.  *    Your shape must not contain a gxQuickDrawPictTag, meaning it contains embedded QD data, becuase
  349.  *    this will potentially crash when it tries to print. To fix that, DecompressShape looks for occurrances
  350.  *    of the tag, and converts them to real gx data by calling GXSetShapeType(shape, gxPictureType).
  351. */
  352. {
  353.     PicHandle                thePicture;
  354.     ImageDescriptionHandle    descHdl;
  355.     ImageDescriptionPtr        descPtr;
  356.     Handle                    dataHdl;
  357.  
  358.     if (!gMachineInfo.haveQuickTime)
  359.         return nil;
  360.  
  361.     /*
  362.      *    Move the shape's topLeft to 0,0 so that it draws neatly inside the picture frame.
  363.      *    Note that the qdgx movie library does not move the shape, since the shape may not
  364.      *    take up the whole frame.
  365.     */
  366.     {    
  367.         gxRectangle    bounds;
  368.  
  369.         GXGetShapeLocalBounds(theShape, &bounds);
  370.         if (bounds.left || bounds.top)
  371.             GXMoveShape(theShape, -bounds.left, -bounds.top);
  372.         dataHdl = CreateQDGXStream(theShape, proxie, forPrintingOnly, eraseBackground);
  373.         if (bounds.left || bounds.top)
  374.             GXMoveShape(theShape, bounds.left, bounds.top);
  375.     }
  376.     if (dataHdl == nil)
  377.         return nil;
  378.  
  379.     descHdl = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  380.     if (descHdl)
  381.         {    
  382.         Rect            shortBounds;
  383.         gxRectangle    bounds;
  384.  
  385.         GXGetShapeLocalBounds(theShape, &bounds);
  386.         RectangleToRect(&bounds, &shortBounds);
  387.         OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top);    // set the topLeft of the src to 0,0
  388.         thePicture = OpenPicture(&shortBounds);
  389.  
  390.         descPtr = *descHdl;
  391.         descPtr->idSize = sizeof(ImageDescription);
  392.         descPtr->cType = 'qdgx';
  393.         descPtr->vendor = 'appl';
  394.         descPtr->temporalQuality = codecLosslessQuality;
  395.         descPtr->width = shortBounds.right;
  396.         descPtr->height = shortBounds.bottom;
  397.         descPtr->hRes = descPtr->vRes = ff(72);
  398.         descPtr->dataSize = GetHandleSize(dataHdl);
  399.         descPtr->frameCount = 1;
  400.         descPtr->depth = 32;
  401.         descPtr->clutID = -1;
  402.  
  403.         //    If there is a PICT proxie, add an image extension to tell QuickTime, in case GX is not around.
  404.         if (proxie)
  405.             {    
  406.             Handle prxyVersionHdl = NewHandle(sizeof(long));
  407.  
  408.             if (prxyVersionHdl != nil)
  409.                 {    
  410.                 *(long*)*prxyVersionHdl = 0;        // version number for 'prxy' extension
  411.                 #if GENERATINGCFM
  412.                     SetImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  413.                 #else
  414.                     AddImageDescriptionExtension(descHdl, prxyVersionHdl, 'prxy');
  415.                 #endif
  416.                 }
  417.             }
  418.  
  419.         HLock(dataHdl);
  420.         DecompressImage(*dataHdl, descHdl, ((CGrafPtr)qd.thePort)->portPixMap, &shortBounds, &shortBounds, srcCopy, nil);
  421.         DisposeHandle((Handle)descHdl);
  422.         ClosePicture();
  423.         }
  424.     else
  425.         thePicture = nil;
  426.  
  427.     DisposeHandle(dataHdl);
  428.  
  429.     return thePicture;
  430.     
  431. } // DecompressShape
  432.  
  433. // --------------------------------------------------------------------------------------------------------------
  434. static PicHandle ShapeToPICT(gxShape source)
  435. /*
  436.  *    This guy returns a Quickdraw picture containing a 1-bit bitmap of the shape.
  437.  *    This is used by ShapeToScrap to create a proxie when calling DecompressShape.
  438.  *    If you want to make the proxie prettier (and larger), change the bitmap to 8-bit.
  439.  *    However, if you're using this in conjunction with DecompressShape to place a
  440.  *    gxShape on the clipboard, 1-bit should be enough, since the actual shape will be
  441.  *    drawn, rather than the proxie (unless forPrintingOnly is true).
  442. */
  443. {
  444.     gxRectangle        bounds;
  445.     gxShape            bitShape;
  446.     gxBitmap        bitmap;
  447.     PicHandle        thePicture;
  448.     Rect            shortBounds;
  449.  
  450.     /*
  451.      *    GetShapeLocalBounds doesn't accurately report the bounds of a gxQuickDrawPictTag.
  452.      *    but we should have none of them at this point anyway.
  453.     */
  454.     GXGetShapeLocalBounds(source, &bounds);
  455.     RectangleToRect(&bounds, &shortBounds);
  456.     OffsetRect(&shortBounds, -shortBounds.left, -shortBounds.top);
  457.  
  458.     bitmap.width        = shortBounds.right;
  459.     bitmap.height        = shortBounds.bottom;
  460.     bitmap.rowBytes        = bitmap.width + 31 >> 5 << 2;
  461.     bitmap.pixelSize    = 1;
  462.     bitmap.space        = gxIndexedSpace;
  463.     bitmap.set            = nil;
  464.     bitmap.profile        = nil;
  465.     bitmap.image        = NewPtrClear(bitmap.rowBytes * bitmap.height);
  466.     if (bitmap.image == nil)
  467.         return nil;
  468.  
  469.     bitShape = GXNewBitmap(&bitmap, nil);
  470.     if (bitShape != nil)
  471.         {    
  472.         gxViewGroup group    = GXNewViewGroup();
  473.         gxViewDevice device    = GXNewViewDevice(group, bitShape);
  474.         gxViewPort port        = GXNewViewPort(group);
  475.         gxTransform trans    = GXCloneTransform(GXGetShapeTransform(source));
  476.  
  477.         GXSetShapeAttributes(source, GXGetShapeAttributes(source) | gxMapTransformShape);
  478.         GXMoveShape(source, -bounds.left, -bounds.top);
  479.         GXSetViewPortDither(port, 4);
  480.         GXSetShapeViewPorts(source, 1, &port);
  481.         GXDrawShape(source);
  482.         GXSetShapeTransform(source, trans);
  483.         GXDisposeTransform(trans);
  484.         
  485.         GXDisposeViewGroup(group);    /* this disposes the gxViewPort and gxViewDevice */
  486.         GXDisposeShape(bitShape);
  487.         }
  488.  
  489.     {    
  490.         GrafPtr    thePort;
  491.         BitMap    srcBits;
  492.     
  493.         GetPort(&thePort);
  494.         srcBits.baseAddr = bitmap.image;
  495.         srcBits.rowBytes = bitmap.rowBytes;
  496.         srcBits.bounds = shortBounds;
  497.  
  498.         thePicture = OpenPicture(&shortBounds);
  499.         CopyBits(&srcBits, &thePort->portBits, &shortBounds, &shortBounds, srcOr, nil);
  500.         ClosePicture();
  501.     }
  502.     
  503.     DisposePtr((Ptr)bitmap.image);
  504.     
  505.     return thePicture;
  506.     
  507. } // ShapeToPICT
  508.  
  509.  
  510.  
  511. // --------------------------------------------------------------------------------------------------------------
  512.  
  513. static void GetRidOfAnyQDShapeTags(gxShape shape)
  514. {
  515.     gxShapeType shapeType = GXGetShapeType(shape);
  516.  
  517.     if (shapeType == gxPictureType)
  518.         {    
  519.         long        index, count;
  520.         gxShape        contentShape;
  521.     
  522.         count = GXGetPicture(shape, nil, nil, nil, nil);
  523.         for (index = 0; index < count; index++)
  524.             {
  525.             GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, nil);
  526.             GetRidOfAnyQDShapeTags(contentShape);
  527.             }
  528.         }
  529.     else 
  530.         {
  531.         if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) )
  532.             GXSetShapeType(shape, gxPictureType);
  533.         }
  534.             
  535. } // GetRidOfAnyQDShapeTags
  536.  
  537. // --------------------------------------------------------------------------------------------------------------
  538.  
  539. static void ShapeToScrap(gxShape source)
  540. /*
  541.  *    This guy puts a Quickdraw picture on the clipboard containing an embedded shape
  542.  *    and, if addProxie is true, a 1-bit bitmap of the shape. Call this in response to
  543.  *    the user choosing "Copy" or "Cut" from the Edit menu. See comment for DecompressShape
  544.  *    to explain forPrintingOnly.
  545. */
  546. {
  547.     PicHandle    picture, proxy;
  548.     
  549.     proxy = ShapeToPICT(source);
  550.     picture = DecompressShape(source, proxy, false, true);
  551.     if (proxy)
  552.         KillPicture(proxy);
  553.  
  554.     if (picture)
  555.         {    
  556.         HLock((Handle)picture);
  557.         ZeroScrap();
  558.         PutScrap(GetHandleSize((Handle)picture), 'PICT', (Ptr)*picture);
  559.         KillPicture(picture);
  560.         }
  561.         
  562. } // ShapeToScrap
  563.  
  564. // --------------------------------------------------------------------------------------------------------------
  565.  
  566. static void CullShape(gxShape shape, gxShape addToThis, gxRectangle *pCullRect, gxStyle cullStyle, gxInk cullInk, gxTransform cullTransform)
  567. /*
  568.     Add to "addToThis" the "shape", only if the shape intersects the pCullRect.
  569. */
  570. {
  571.     gxShapeType shapeType = GXGetShapeType(shape);
  572.  
  573.     if (shapeType == gxPictureType)
  574.         {    
  575.         long        index, count;
  576.         gxShape        contentShape;
  577.     
  578.         count = GXGetPicture(shape, nil, nil, nil, nil);
  579.         for (index = 0; index < count; index++)
  580.             {
  581.             GXGetPictureParts(shape, index+1, 1, &contentShape, &cullStyle, &cullInk, &cullTransform);
  582.             CullShape(contentShape, addToThis, pCullRect, cullStyle, cullInk, cullTransform);
  583.             }
  584.         }
  585.     else 
  586.         {
  587.         gxRectangle    bounds;
  588.         
  589.         GXGetShapeLocalBounds(shape, &bounds);
  590.         
  591.         if (IsSomewhereInRectangle(pCullRect, &bounds))
  592.             {
  593.             if ( (shapeType == gxRectangleType) && (GXGetShapeTags(shape, gxQuickDrawPictTag, 1, gxSelectToEnd, nil) > 0) )
  594.                 {
  595.                 // convert shape and add -- but only if it goes okay
  596.                 GXSetShapeType(shape, gxPictureType);
  597.                 if (GXGetShapeType(shape) == gxPictureType)
  598.                     CullShape(shape, addToThis, pCullRect, cullStyle, cullInk, cullTransform);
  599.                 }
  600.             else
  601.                 {
  602.                 GXSetPictureParts(addToThis, 0, 0, 1, &shape, &cullStyle, &cullInk, &cullTransform);
  603.                 }
  604.             }
  605.         }
  606.         
  607. } // CullShape
  608.  
  609. // --------------------------------------------------------------------------------------------------------------
  610. static gxShape CullPicture(gxShape pictureShape, gxRectangle * pCullRect)
  611. /*
  612.     Returns a new shape that is all of the shapes inside of pictureShape
  613.     that intersect pCullRect.
  614. */
  615. {
  616.     gxShape        newPicture = GXNewShape(gxPictureType);
  617.     gxShape     clipShape = GXNewRectangle(pCullRect);
  618.     gxMapping    mapping;
  619.     gxRectangle    clipRect;
  620.     
  621.     // new shape as same mapping as old one
  622.     GXGetTransformMapping(GXGetShapeTransform(pictureShape), &mapping);
  623.     GXSetShapeMapping(newPicture, &mapping);
  624.     
  625.     // clip also has the mapping, but inverted so that it's the right space
  626.     InvertMapping(&mapping, &mapping);
  627.     GXMapShape(clipShape, &mapping);
  628.     GXGetShapeLocalBounds(clipShape, &clipRect);
  629.     
  630.     // clip to the selection
  631.     GXSetShapeClip(newPicture, clipShape);
  632.     GXDisposeShape(clipShape);
  633.  
  634.     // add all shapes that intersect the clip area
  635.     CullShape(pictureShape, newPicture, &clipRect, nil, nil, nil);
  636.         
  637.     // new shape is zero based
  638.     GXMoveShape(newPicture, -pCullRect->left, -pCullRect->top);
  639.     
  640.     return(newPicture);
  641.     
  642. } // CullPicture
  643.  
  644. // --------------------------------------------------------------------------------------------------------------
  645. static gxShape GetSelectedShape(WindowDataPtr pData)
  646. /*
  647.     Returns a shape that represents all shapes on the current page
  648.     that are contained by the current selection rectangle.
  649. */
  650. {
  651.     gxRectangle        cullRect;
  652.     gxShape            cullShape;
  653.     gxPoint            offset;
  654.     Fixed            zoomFactor = ((GXDataPtr)pData)->zoomFactor;
  655.     
  656.     // calculate the actual coodinate space, removing margins
  657.     {
  658.     gxRectangle        pageSize, paperSize;
  659.     
  660.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  661.     offset.y = FixedMultiply(-paperSize.top, zoomFactor);
  662.     offset.x = FixedMultiply(-paperSize.left, zoomFactor);
  663.     }
  664.     
  665.     // calculate the actual coodinates to copy
  666.     cullRect.top    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.top) - offset.y, zoomFactor);
  667.     cullRect.left    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.left) - offset.x, zoomFactor);
  668.     cullRect.bottom    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.bottom) - offset.y, zoomFactor);
  669.     cullRect.right    = FixedDivide(ff(((GXDataPtr)pData)->selectionRectangle.right) - offset.x, zoomFactor);
  670.     
  671.     // chop the data
  672.     cullShape = CullPicture(((GXDataPtr)pData)->currentPageShape, &cullRect);
  673.     
  674.     return(cullShape);
  675.     
  676. } // GetSelectedShape
  677.  
  678. // --------------------------------------------------------------------------------------------------------------
  679. static pascal OSErr GXSendDataProc(FlavorType theType, void *dragSendRefCon,
  680.                                 ItemReference theItem, DragReference theDrag)
  681. /*
  682.  *    The ItemReference is the gxShape to be sent. The dragSendRefCon is ignored.
  683. */
  684. {
  685. #pragma unused (dragSendRefCon)
  686.  
  687.     OSErr    result = noErr;
  688.     gxShape    shape = ((GXDataPtr)theItem)->tempDragShape;
  689.     
  690.     // haven't made clipped version yet?
  691.     if (shape == nil)
  692.         {
  693.         shape = GetSelectedShape((WindowDataPtr) theItem);
  694.         ((GXDataPtr)theItem)->tempDragShape = shape;
  695.         }
  696.         
  697.     switch (theType) 
  698.         {
  699.         case 'qdgx':
  700.             {    
  701.             Handle         flat;
  702.               userSpool     block;
  703.  
  704.             block.spool.spoolProcedure = gHandleSpoolProc;
  705.             block.spool.buffer = nil;
  706.             block.spool.bufferSize = 0;
  707.             GXFlattenShape(shape, gxFontListFlatten | gxFontGlyphsFlatten | gxFontVariationsFlatten, &block.spool);
  708.             flat = (Handle) block.data;
  709.     
  710.             if (flat)
  711.                 {    
  712.                 HLock(flat);
  713.                 result = SetDragItemFlavorData(theDrag, theItem, 'qdgx', *flat, GetHandleSize(flat), 0);
  714.                 DisposeHandle(flat);
  715.                 }
  716.             }
  717.             break;
  718.             
  719.         case 'PICT':
  720.             {    
  721.             PicHandle proxie = ShapeToPICT(shape);
  722.             PicHandle pict = DecompressShape(shape, proxie, false, true);
  723.     
  724.             if (proxie)
  725.                 KillPicture(proxie);
  726.             if (pict)
  727.                 {    
  728.                 HLock((Handle)pict);
  729.                 result = SetDragItemFlavorData(theDrag, theItem, 'PICT', (Ptr)*pict, GetHandleSize((Handle)pict), 0);
  730.                 KillPicture(pict);
  731.                 }
  732.             }
  733.             break;
  734.             
  735.         default:
  736.             result = badDragFlavorErr;
  737.             break;
  738.         }
  739.             
  740.     return result;
  741.     
  742. } // GXSendDataProc
  743.  
  744. #if GENERATINGCFM
  745.     static RoutineDescriptor gGXSendDataProcRD = BUILD_ROUTINE_DESCRIPTOR(uppDragSendDataProcInfo, GXSendDataProc);
  746.     static DragSendDataUPP gGXSendDataProc = &gGXSendDataProcRD;
  747. #else
  748.     static DragSendDataUPP gGXSendDataProc = NewDragSendDataProc(GXSendDataProc);
  749. #endif
  750.  
  751. // --------------------------------------------------------------------------------------------------------------
  752. static void ClearCurrentSelection(GXDataPtr pData)
  753. {
  754.     pData->currentShapeIndex = 0;
  755.     pData->currentShapeStart = 0;
  756.     pData->currentShapeEnd = 0;
  757.     if (pData->currentSelectionShape)
  758.         {
  759.         GXDisposeShape(pData->currentSelectionShape);
  760.         pData->currentSelectionShape = nil;
  761.         }
  762.         
  763. } // ClearCurrentSelection
  764.  
  765. // --------------------------------------------------------------------------------------------------------------
  766. static OSErr    GetCurrentPage(GXDataPtr pData, Boolean disposeOfSelection)
  767. /*
  768.     Disposes of previously loaded page information, and loads the
  769.     page information for the current page number.
  770. */
  771. {
  772.     OSErr        anErr;
  773.     LongRect    oldRect, newRect;
  774.     
  775.     if (pData->numberOfPages != 0)
  776.         {
  777.         // get rid of any previous format
  778.         if (pData->currentPageFormat)
  779.             {
  780.             GXDisposeFormat(pData->currentPageFormat);
  781.             pData->currentPageFormat = nil;
  782.             }
  783.             
  784.         // get rid of any previous shape
  785.         if (pData->currentPageShape)
  786.             {
  787.             GXDisposeShape(pData->currentPageShape);
  788.             pData->currentPageShape = nil;
  789.             }
  790.             
  791.         // get rid of selection, if desired
  792.         if (disposeOfSelection)
  793.             ClearCurrentSelection(pData);
  794.  
  795.         GXGetDocumentRect((WindowRef)pData, (WindowDataPtr)pData, &oldRect, false);
  796.         
  797.         GXReadPrintFilePage(pData->thePrintFile, 
  798.             pData->currentPage, 
  799.             1, &pData->childViewPort, 
  800.             &pData->currentPageFormat, &pData->currentPageShape);
  801.         }
  802.         
  803.     anErr = GXGetJobError(pData->w.hPrint);
  804.     
  805.     if (anErr == noErr)
  806.         {
  807.         GXGetDocumentRect((WindowRef)pData,(WindowDataPtr) pData, &newRect, false);
  808.         
  809.         if     (
  810.             (oldRect.left != newRect.left) ||
  811.             (oldRect.top != newRect.top) ||
  812.             (oldRect.right != newRect.right) ||
  813.             (oldRect.bottom != newRect.bottom)
  814.             )
  815.             {
  816.             // if the resulting page is < the current window size, we need to resize,
  817.             long newWidth     = newRect.right - newRect.left + kScrollBarSize;
  818.             long newHeight     = newRect.bottom - newRect.top + kScrollBarSize;
  819.             long oldWidth     = pData->w.theWindow.port.portRect.right - pData->w.theWindow.port.portRect.left;
  820.             long oldHeight     = pData->w.theWindow.port.portRect.bottom - pData->w.theWindow.port.portRect.top;
  821.             
  822.             // but don't let it get too small!
  823.             if (newWidth < pData->w.minHSize)
  824.                 newWidth = pData->w.minHSize;
  825.             if (newHeight < kMinGXDocSize)
  826.                 newHeight = kMinGXDocSize;
  827.                 
  828.             if     (
  829.                 (newWidth < oldWidth) ||
  830.                 (newHeight < oldHeight)
  831.                 )
  832.                 {
  833.                 if (newWidth > oldWidth)
  834.                     newWidth = oldWidth;
  835.                 if (newHeight > oldHeight)
  836.                     newHeight = oldHeight;
  837.                     
  838.                 SizeWindow((WindowRef)pData, newWidth, newHeight, false);
  839.                 }
  840.                 
  841.             // and in any case, the scroll bars should update
  842.             AdjustScrollBars((WindowRef)pData, true, true, nil);
  843.             }
  844.         }
  845.         
  846.     return(anErr);
  847.     
  848. } // GetCurrentPage
  849.  
  850. // --------------------------------------------------------------------------------------------------------------
  851. #define charBullet    '•'
  852.  
  853. static void GetIntlTokenChar(short whichToken, short whichScript, char *bulletString)
  854. //
  855. // GetIntlTokenChar
  856. //
  857. // This routine gets a character out of the itl4 given a script and token…
  858. //
  859. {
  860.     Handle    itl4H;
  861.     long    offset, len;
  862.  
  863.     // default the value
  864.     bulletString[0] = 1;
  865.     bulletString[1] = charBullet;
  866.     
  867.     // Look up the untoken table -- bail if we can’t get it
  868.     GetIntlResourceTable(whichScript, iuUnTokenTable, &itl4H, &offset, &len);
  869.     if (itl4H && (offset > 0) && (len >= 0))
  870.     {
  871.         char *sp = (*itl4H + offset);                // Point to start of untoken table
  872.         if (whichToken <= ((short *)sp)[1])            // Check if token has valid index
  873.         {
  874.             sp += ((short *)sp)[2+whichToken];        // Add the string offset and voliá!
  875.             BlockMoveData(sp, bulletString, sp[0]+1);
  876.         }
  877.     }
  878.     
  879. } // GetIntlTokenChar
  880.  
  881. // --------------------------------------------------------------------------------------------------------------
  882. // This code is required to change pop up menus to a different font size.  It would be
  883. // better to use the pop up control, but it doesn't allow multiple items to be marked.
  884.  
  885. #define SysFontSize    0xBA8
  886. #define SysFontFam    0xBA6
  887. #define CurFMInput    0x988
  888.  
  889. static void DoUseWFont(TextState *savedInfo, WindowRef owner,  Boolean saveIt)
  890. /*************************************************************
  891.     DoUseWFont        - Sets the font mgr low mem globals so
  892.                         we can have Geneva 9 popups
  893.  
  894.         savedInfo    - Fills it in if saveIt = true, else
  895.                         it sets the port to those values
  896.         owner        - Where to get the original values
  897.         saveIt        - true for save
  898. **************************************************************/
  899. {
  900.     TextState        myState,
  901.                     *theState;
  902.     short            aFont;
  903.  
  904.     theState = savedInfo;
  905.  
  906.     if (saveIt) 
  907.         {
  908.         savedInfo->theFont = GetSysFont();    // save low memory globals
  909.         savedInfo->theSize = *((short *) SysFontSize);
  910.  
  911.         myState.theFont = GetWindowPort(owner)->txFont;
  912.         myState.theSize = GetWindowPort(owner)->txSize;
  913.         theState = &myState;
  914.  
  915.         // if we stuff systemFont, it will screw up Script Mgr
  916.         if (GetWindowPort(owner)->txFont == systemFont)
  917.             goto dosizestuff;
  918.         }
  919.  
  920.     // if we stuff applFont, this will also screw up Script Mgr
  921.     // instead we get the actual font
  922.     aFont = theState->theFont;
  923.     if (saveIt)
  924.         if (GetWindowPort(owner)->txFont == applFont)
  925.             aFont = GetAppFont();
  926.     *((short *) SysFontFam) = aFont;                    // set/restore low memory globals
  927.  
  928. dosizestuff:
  929.     *((short *) SysFontSize) = theState->theSize;
  930.  
  931.     *((long *) CurFMInput) = 0xFFFFFFFF;
  932.     
  933. } // DoUseWFont
  934.  
  935.  
  936. // --------------------------------------------------------------------------------------------------------------
  937.  
  938. static void SetZoom(WindowRef pWindow, WindowDataPtr pData, Fixed newZoom)
  939. /*
  940.     Sets the new zoom factor for the window, causing an update for
  941.     the window if required.
  942. */
  943. {
  944.     Fixed    scaleFactor;
  945.     
  946.     // pin to max/min zoom factors
  947.     if (newZoom > ff(32))
  948.         newZoom = ff(32);
  949.     if (newZoom < 0x0800)
  950.         newZoom = 0x0800;
  951.     
  952.     scaleFactor = FixedDivide(newZoom, ((GXDataPtr)pData)->zoomFactor);
  953.     
  954.     if (scaleFactor != ff(1))
  955.         {
  956.         gxPoint        centerPoint;
  957.         GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  958.         
  959.         // zoom about the window center
  960.         centerPoint.x = ff(pPort->portRect.left + (RectWidth(pPort->portRect) >> 1));
  961.         centerPoint.y = ff(pPort->portRect.top + (RectHeight(pPort->portRect) >> 1));
  962.         
  963.         // new zoom active
  964.         ((GXDataPtr)pData)->zoomFactor = newZoom;
  965.         
  966.         // force update and recalc the size of window
  967.         InvalRect(&pPort->portRect);
  968.         AdjustScrollBars(pWindow, true, true, nil);
  969.  
  970.          // scale scroll values
  971.         SetControlValue(pData->hScroll, FixedToInt( FixedDivide(centerPoint.x, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->hScroll)), scaleFactor) ) );
  972.         SetControlValue(pData->vScroll, FixedToInt( FixedDivide(centerPoint.y, scaleFactor) + FixedMultiply(ff(GetControlValue(pData->vScroll)), scaleFactor) ) );
  973.         
  974.         // zoom the selection
  975.         ((GXDataPtr)pData)->selectionRectangle.left     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.left), scaleFactor) );
  976.         ((GXDataPtr)pData)->selectionRectangle.top         = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.top), scaleFactor) );
  977.         ((GXDataPtr)pData)->selectionRectangle.right     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.right), scaleFactor) );
  978.         ((GXDataPtr)pData)->selectionRectangle.bottom     = FixedToInt (FixedMultiply(ff(((GXDataPtr)pData)->selectionRectangle.bottom), scaleFactor) );
  979.         }
  980.     
  981. } // SetZoom
  982.  
  983. // --------------------------------------------------------------------------------------------------------------
  984.  
  985. static void SetShapeGreyColorLevel(gxShape thisShape, unsigned long greyLevel)
  986. {
  987.     gxColor thisColor;
  988.  
  989.     thisColor.space = gxGraySpace;
  990.     thisColor.profile = nil;
  991.     thisColor.element.gray = greyLevel;
  992.     GXSetShapeColor(thisShape, &thisColor);
  993.     
  994. } // SetShapeGreyColorLevel
  995.  
  996. // --------------------------------------------------------------------------------------------------------------
  997. static void    CenterRect(Rect *source, Rect *against)
  998. /*
  999.     Centers "source" within or around "against".
  1000. */
  1001. {
  1002.     // center picture if requested
  1003.     short    height, width, pheight, pwidth;
  1004.     
  1005.     height = (against->bottom - against->top) >> 1;
  1006.     width = (against->right - against->left) >> 1;
  1007.     pheight = (source->bottom - source->top) >> 1;
  1008.     pwidth = (source->right - source->left) >> 1;
  1009.     
  1010.     source->top = against->top + height - pheight;
  1011.     source->bottom = against->bottom - height + pheight;
  1012.     source->left = against->left + width - pwidth;
  1013.     source->right = against->right - width + pwidth;
  1014.  
  1015. } // CenterRect
  1016.  
  1017. // --------------------------------------------------------------------------------------------------------------
  1018.  
  1019. static gxShape FindNestedIndexedLayout(gxShape shape, 
  1020.                     long searchIndex, long * pIndex, gxMapping *pConcatMapping)
  1021. /*
  1022.     Returns the shape represented by "searchIndex" shapes into the picture,
  1023.     sequentially, including all nestings of pictures.  Uses pIndex as
  1024.     work storage, which must be initialized to zero before the call.
  1025.     
  1026.     Returns shape found, or NIL if the searchIndex is larger than
  1027.     the number of shapes in the picture.  If NIL is returned,
  1028.     then the contents of pIndex will contain the number of
  1029.     shapes in the picture.
  1030. */
  1031. {
  1032.     gxShape        returnShape = nil;
  1033.     gxShapeType shapeType = GXGetShapeType(shape);
  1034.  
  1035.     // bail on negative index
  1036.     if (searchIndex < 0)
  1037.         return(nil);
  1038.         
  1039.     if (shapeType == gxPictureType)
  1040.         {    
  1041.         long        index, count;
  1042.         gxShape        contentShape;
  1043.         gxTransform    contentTransform;
  1044.         gxMapping    contentMapping;
  1045.         
  1046.         count = GXGetPicture(shape, nil, nil, nil, nil);
  1047.         for (index = 0; index < count; index++)
  1048.             {
  1049.             GXGetPictureParts(shape, index+1, 1, &contentShape, nil, nil, &contentTransform);
  1050.             
  1051.             returnShape = FindNestedIndexedLayout(contentShape, searchIndex, pIndex, pConcatMapping ? &contentMapping : nil);
  1052.             if (returnShape)
  1053.                 {
  1054.                 if (pConcatMapping)
  1055.                     {
  1056.                     if (!contentTransform)
  1057.                         contentTransform = GXGetShapeTransform(contentShape);
  1058.                     GXGetTransformMapping(contentTransform, &contentMapping);
  1059.                     MapMapping(&contentMapping, pConcatMapping);
  1060.                     *pConcatMapping = contentMapping;
  1061.                     }
  1062.                 break;
  1063.                 }
  1064.             }
  1065.         }
  1066.     else 
  1067.         {
  1068.         if ( (shapeType == gxLayoutType) || (shapeType == gxGlyphType) || (shapeType == gxTextType) )
  1069.             {
  1070.             (*pIndex)++;
  1071.             if (searchIndex == *pIndex)
  1072.                 returnShape = shape;
  1073.             }
  1074.         }
  1075.         
  1076.     return(returnShape);
  1077.     
  1078. } // FindNestedIndexedLayout
  1079.  
  1080. // --------------------------------------------------------------------------------------------------------------
  1081. static Boolean PerformNextFind(WindowRef pWindow, WindowDataPtr pData,
  1082.                 Str255 findString,
  1083.                 Boolean caseSensitive,
  1084.                 Boolean backwards,
  1085.                 Boolean wraparound)
  1086. {
  1087.     Boolean    foundSomething = false;
  1088.     long    searchIndex, workIndex;
  1089.     gxShape    aShape;
  1090.     long    direction;
  1091.     long    oldPageNumber = ((GXDataPtr)pData)->currentPage;
  1092.     long    endPageNumber;
  1093.     Boolean    firstTime = true;
  1094.     gxMapping    concatMapping;
  1095.     
  1096.     // initialize direction of the walk
  1097.     if (backwards)
  1098.         direction = -1;
  1099.     else
  1100.         direction = 1;
  1101.     
  1102.     // start searching where we last left off    
  1103.     searchIndex = ((GXDataPtr)pData)->currentShapeIndex;
  1104.     if (searchIndex != 0)
  1105.         searchIndex -= direction;
  1106.     
  1107.     if (((GXDataPtr)pData)->numberOfPages == 1)
  1108.         wraparound = false;
  1109.  
  1110.     // end searching on a particular page
  1111.     if (backwards)
  1112.         endPageNumber = 0;
  1113.     else
  1114.         endPageNumber = ((GXDataPtr)pData)->numberOfPages + 1;
  1115.     
  1116.     // can't search on qd shapes, so we get rid of them
  1117.     GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape);
  1118.  
  1119.     do
  1120.         {
  1121.         // search for the next shape or prev shape
  1122.         searchIndex += direction;
  1123.         
  1124.         // initialize the working index so that we know traversal level
  1125.         workIndex = 0;
  1126.         
  1127.         // initialize the mapping to identity
  1128.         ResetMapping(&concatMapping);
  1129.         GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &concatMapping);
  1130.         
  1131.         // find the next layout in the page
  1132.         aShape = FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, searchIndex, &workIndex, &concatMapping);
  1133.         if (aShape)
  1134.             {
  1135.             gxShapeType shapeType = GXGetShapeType(aShape);
  1136.             long          size;
  1137.             Handle        aHandle;
  1138.             
  1139.             // determine size and allocate storage for layout contents
  1140.             switch (shapeType)
  1141.                 {
  1142.                 case gxTextType:
  1143.                     size = GXGetText(aShape, nil, nil, nil);
  1144.                     break;
  1145.                 case gxGlyphType:
  1146.                     size = GXGetGlyphs(aShape, nil, nil, nil,
  1147.                                     nil, nil, nil, nil, nil);
  1148.                     break;
  1149.                 case gxLayoutType:
  1150.                     size = GXGetLayout(aShape, nil,
  1151.                                     nil, nil, nil,     // styles
  1152.                                     nil, nil, nil,     // levels
  1153.                                     nil, nil);        // options/position
  1154.                     break;
  1155.                 }
  1156.             aHandle = NewHandle(size);
  1157.             
  1158.             if (aHandle)
  1159.                 {
  1160.                 long newStart, newEnd;
  1161.                 
  1162.                 // grab the contents of the layout into the temp storage
  1163.                 HLock(aHandle);
  1164.                 switch (shapeType)
  1165.                     {
  1166.                     case gxTextType:
  1167.                         GXGetText(aShape, nil, (unsigned char*)*aHandle, nil);
  1168.                         break;
  1169.                     case gxGlyphType:
  1170.                         GXGetGlyphs(aShape, nil,  (unsigned char*)*aHandle, nil,
  1171.                                         nil, nil, nil, nil, nil);
  1172.                         break;
  1173.                     case gxLayoutType:
  1174.                         GXGetLayout(aShape,  (unsigned char*)*aHandle,
  1175.                                     nil, nil, nil,     // styles
  1176.                                     nil, nil, nil,     // levels
  1177.                                     nil, nil);        // options/position
  1178.                         break;
  1179.                     }
  1180.                 HUnlock(aHandle);
  1181.                 
  1182.                 // search the handle for the string we're looking for,
  1183.                 // but don't wraparound because we handle that over layout
  1184.                 // ranges and pages ourselves
  1185.                 {
  1186.                 long offset;
  1187.                 
  1188.                 if ((firstTime) && (((GXDataPtr)pData)->currentSelectionShape))
  1189.                     {
  1190.                     // for shape that we have found something in before
  1191.                     // start at end of last point if forwards, start of last point
  1192.                     // if backwards
  1193.                     firstTime = false;
  1194.                     offset = backwards ? ((GXDataPtr)pData)->currentShapeStart : ((GXDataPtr)pData)->currentShapeEnd;
  1195.                     }
  1196.                 else
  1197.                     {
  1198.                     // for "new" shape we haven't hit before, start at
  1199.                     // begining for forwards, end for backwards
  1200.                     offset = backwards ? size : 0;
  1201.                     }
  1202.                     
  1203.                 foundSomething = PerformSearch(aHandle, offset, findString, 
  1204.                             caseSensitive, backwards, false,
  1205.                             &newStart, &newEnd);
  1206.                 }
  1207.                             
  1208.                 // done with our temp storage
  1209.                 DisposeHandle(aHandle);
  1210.                 
  1211.                 // got it?  then mark it and bail out
  1212.                 if (foundSomething)
  1213.                     {
  1214.                     // remember where we are in the page
  1215.                     ((GXDataPtr)pData)->currentShapeIndex = searchIndex;
  1216.                     
  1217.                     // what offsets the selection is
  1218.                     ((GXDataPtr)pData)->currentShapeStart = newStart;
  1219.                     ((GXDataPtr)pData)->currentShapeEnd = newEnd;
  1220.                     
  1221.                     // and the shape containing the selection
  1222.                     if (((GXDataPtr)pData)->currentSelectionShape)
  1223.                         GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape);
  1224.                     ((GXDataPtr)pData)->currentSelectionShape = GXCloneShape(aShape);
  1225.                     ((GXDataPtr)pData)->currentSelectionMapping = concatMapping;
  1226.                     break;
  1227.                     } // found the string
  1228.                     
  1229.                 } // allocated the handle
  1230.                 
  1231.             } // found a shape
  1232.         else
  1233.             {
  1234.             OSErr    anErr = noErr;
  1235.             
  1236.             // didn't find it on this page, move on
  1237.             ((GXDataPtr)pData)->currentPage += direction;
  1238.             
  1239.                 
  1240.             // clamp to the ends of the range
  1241.             if (backwards)
  1242.                 {
  1243.                 if (((GXDataPtr)pData)->currentPage <= endPageNumber)
  1244.                     {
  1245.                     if (wraparound)
  1246.                         {
  1247.                         ((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages;
  1248.                         endPageNumber = oldPageNumber;
  1249.                         wraparound = false;
  1250.                         }
  1251.                     else
  1252.                         anErr = paramErr;
  1253.                     }
  1254.                 }
  1255.             else
  1256.                 {
  1257.                 if (((GXDataPtr)pData)->currentPage >= endPageNumber)
  1258.                     {
  1259.                     if (wraparound)
  1260.                         {
  1261.                         ((GXDataPtr)pData)->currentPage = 1;
  1262.                         endPageNumber = oldPageNumber;
  1263.                         wraparound = false;
  1264.                         }
  1265.                     else
  1266.                         anErr = paramErr;
  1267.                     }
  1268.                 }
  1269.                 
  1270.             // fetch contents
  1271.             if (anErr == noErr)
  1272.                 anErr = GetCurrentPage((GXDataPtr) pData, false);
  1273.                 
  1274.             // anything wrong?  then all done searching
  1275.             if (anErr != noErr)
  1276.                 {
  1277.                 break;
  1278.                 }
  1279.             else
  1280.                 {
  1281.                 GetRidOfAnyQDShapeTags(((GXDataPtr)pData)->currentPageShape);
  1282.                 if (backwards)
  1283.                     {
  1284.                     workIndex = 0;
  1285.                     (void) FindNestedIndexedLayout(((GXDataPtr)pData)->currentPageShape, 0x7FFFFFF, &workIndex, nil);
  1286.                     searchIndex = workIndex;
  1287.                     }
  1288.                 else
  1289.                     searchIndex = 0;
  1290.                 }
  1291.             }
  1292.         } while (!foundSomething);
  1293.     
  1294.     // if we found something, force and update.  If not, make sure
  1295.     // that the current page is restored to the page we had when 
  1296.     // coming in.
  1297.     if (foundSomething)
  1298.         {
  1299.         InvalRect(&GetWindowPort(pWindow)->portRect);
  1300.         }
  1301.     else
  1302.         {
  1303.         if (oldPageNumber != ((GXDataPtr)pData)->currentPage)
  1304.             {
  1305.             ((GXDataPtr)pData)->currentPage = oldPageNumber;
  1306.             GetCurrentPage((GXDataPtr) pData, false);
  1307.             }
  1308.         }
  1309.     return(foundSomething);
  1310.     
  1311. } // PerformNextFind
  1312.  
  1313. // --------------------------------------------------------------------------------------------------------------
  1314. static gxShape GetCurrentSelectionHighlight(WindowDataPtr pData, Boolean mapIt)
  1315. {
  1316.     gxShape        highlight;
  1317.     
  1318.     highlight = GXGetLayoutHighlight(((GXDataPtr)pData)->currentSelectionShape, 
  1319.                         ((GXDataPtr)pData)->currentShapeStart, ((GXDataPtr)pData)->currentShapeEnd,
  1320.                         gxHighlightAverageAngle, nil);
  1321.                         
  1322.     
  1323.     if (mapIt)
  1324.         GXMapShape(highlight, &((GXDataPtr)pData)->currentSelectionMapping);
  1325.     
  1326.     // draw and dispose of the highlight
  1327.     GXSetShapeViewPorts(highlight, 1, &((GXDataPtr)pData)->childViewPort);
  1328.     GXSetShapeFill(highlight, gxClosedFrameFill);
  1329.     GXSetShapeClip(highlight, nil);
  1330.  
  1331.     return(highlight);
  1332.     
  1333. } // GetCurrentSelectionHighlight
  1334.  
  1335. // --------------------------------------------------------------------------------------------------------------
  1336. static void ScrollFoundShapeIntoView(WindowRef pWindow, WindowDataPtr pData)
  1337. {
  1338.     gxRectangle    bounds;
  1339.     Point        scrollAmount;
  1340.     Point        controlValues;
  1341.     gxRectangle    windowBounds;
  1342.     GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  1343.     
  1344.     if ( ! (((GXDataPtr)pData)->currentSelectionShape) )
  1345.         return;
  1346.         
  1347.     // cache scroll state
  1348.     controlValues.h = GetControlValue(pData->hScroll);
  1349.     controlValues.v = GetControlValue(pData->vScroll);
  1350.     
  1351.     // calculate visible bounds of window
  1352.     windowBounds.left         = ff(pPort->portRect.left + controlValues.h);
  1353.     windowBounds.right         = ff(pPort->portRect.right - kScrollBarSize + controlValues.h);
  1354.     windowBounds.top         = ff(pPort->portRect.top + controlValues.v);
  1355.     windowBounds.bottom     = ff(pPort->portRect.bottom - kScrollBarSize + controlValues.v);                
  1356.  
  1357.     // grab the bounds of the shape, add on the margins, scale to zoom factor
  1358.     {
  1359.     gxRectangle        pageSize, paperSize;
  1360.     gxShape            highlight = GetCurrentSelectionHighlight(pData, false);
  1361.     
  1362.     GXGetShapeBounds(highlight, 0, &bounds);
  1363.     GXDisposeShape(highlight);
  1364.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  1365.     bounds.left     = FixedMultiply(bounds.left - paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  1366.     bounds.right     = FixedMultiply(bounds.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  1367.     bounds.top         = FixedMultiply(bounds.top - paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  1368.     bounds.bottom     = FixedMultiply(bounds.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  1369.     }
  1370.  
  1371.     if     (
  1372.         (bounds.bottom <= windowBounds.top) ||
  1373.         (bounds.top >= windowBounds.bottom) ||
  1374.         (bounds.right <= windowBounds.left) ||
  1375.         (bounds.left >= windowBounds.right) 
  1376.         )
  1377.         {
  1378.         scrollAmount.h = controlValues.h - FixedToInt(bounds.left);
  1379.         scrollAmount.v = controlValues.v - FixedToInt(bounds.top);
  1380.         
  1381.         SetControlAndClipAmount(pData->hScroll, &scrollAmount.h);
  1382.         SetControlAndClipAmount(pData->vScroll, &scrollAmount.v);
  1383.         if ((scrollAmount.h) || (scrollAmount.v))
  1384.             DoScrollContent(pWindow, pData, scrollAmount.h, scrollAmount.v);
  1385.         }
  1386.         
  1387. } // ScrollFoundShapeIntoView
  1388.  
  1389. // --------------------------------------------------------------------------------------------------------------
  1390. static Boolean TrackIn(Rect *pTrackRect, Point clickPoint, Rect *pDrawRect, short inID, short outID)
  1391. {
  1392.     Boolean    in = false;
  1393.     
  1394.     if (PtInRect(clickPoint, pTrackRect))
  1395.         {
  1396.         in = true;
  1397.         
  1398.         PlotIconID(pDrawRect, ttNone, ttNone, inID);
  1399.         while (StillDown())
  1400.             {
  1401.             GetMouse(&clickPoint);
  1402.             
  1403.             if (PtInRect(clickPoint, pTrackRect))
  1404.                 {
  1405.                 if (!in)
  1406.                     {
  1407.                     in = true;
  1408.                     PlotIconID(pDrawRect, ttNone, ttNone, inID);
  1409.                     }
  1410.                 }
  1411.             else
  1412.                 {
  1413.                 if (in)
  1414.                     {
  1415.                     in = false;
  1416.                     PlotIconID(pDrawRect, ttNone, ttNone, outID);
  1417.                     }
  1418.                 }
  1419.             }
  1420.         }
  1421.         
  1422.     return(in);
  1423.     
  1424. } // TrackIn
  1425.  
  1426. // --------------------------------------------------------------------------------------------------------------
  1427. static void DrawPageSliderAndThumb(WindowRef pWindow, long currentValue, long maxValue)
  1428. {
  1429.     Rect        pageSliderRect;
  1430.     Rect        pageThumbRect;
  1431.     long        pixelValue;
  1432.     Str255        aString;
  1433.     FontInfo    theInfo;
  1434.     PicHandle    proxyHandle;
  1435.     Rect        proxyRect;
  1436.     GrafPtr        pPort = (GrafPtr)GetWindowPort(pWindow);
  1437.     
  1438.     // calculate location of the slider
  1439.     pageSliderRect.left     = kPageSliderMargins;
  1440.     pageSliderRect.bottom     = pPort->portRect.bottom - kPageSliderMargins;
  1441.     pageSliderRect.top         = pageSliderRect.bottom - kPageSliderHeight;
  1442.     pageSliderRect.right     = pPort->portRect.right - kPageSliderMargins;
  1443.         
  1444.     // then calculate the thumb within that slider
  1445.     pixelValue = (currentValue-1) 
  1446.                 *
  1447.                 (pageSliderRect.right - pageSliderRect.left - kPageThumbMargins*2 - kPageThumbWidth) 
  1448.                 /
  1449.                 (maxValue-1);
  1450.                 
  1451.     pageThumbRect.left         = pageSliderRect.left + kPageThumbMargins + pixelValue;
  1452.     pageThumbRect.right        = pageThumbRect.left + kPageThumbWidth;
  1453.     pageThumbRect.top        = pageSliderRect.top - kPageThumbEdge;
  1454.     pageThumbRect.bottom    = pageThumbRect.top + kPageThumbHeight;
  1455.  
  1456.     // and finally, the location to draw the proxy (if any)
  1457.     proxyRect.top            = kPageSliderMargins;
  1458.     proxyRect.bottom        = proxyRect.top + kProxyHeight;
  1459.     proxyRect.left            = pPort->portRect.left + 
  1460.                                 ((pPort->portRect.right - pPort->portRect.left) >> 1) -
  1461.                                 (kProxyWidth >> 1);
  1462.     proxyRect.right            = proxyRect.left + kProxyWidth;
  1463.     if (Count1Resources(kProxyType) == 0)
  1464.         proxyRect.bottom = proxyRect.top;
  1465.         
  1466.     // draw the slider area
  1467.     FillRect(&pageSliderRect, &qd.gray);
  1468.     FrameRect(&pageSliderRect);
  1469.  
  1470.     // erase areas above and below the slider (old thumb erase)
  1471.     {
  1472.     Rect    sliderEraseRect = pageSliderRect;
  1473.     
  1474.     ForeColor(whiteColor);
  1475.     sliderEraseRect.top = pageThumbRect.top;
  1476.     sliderEraseRect.bottom = sliderEraseRect.top + kPageThumbEdge;
  1477.     PaintRect(&sliderEraseRect);
  1478.     sliderEraseRect.bottom = pageThumbRect.bottom;
  1479.     sliderEraseRect.top = sliderEraseRect.bottom - kPageThumbEdge;
  1480.     PaintRect(&sliderEraseRect);
  1481.     }
  1482.     
  1483.     // draw the thumb
  1484.     ForeColor(blackColor);
  1485.     FrameRect(&pageThumbRect);
  1486.     InsetRect(&pageThumbRect, 1, 1);
  1487.     ForeColor(whiteColor);
  1488.     FrameRect(&pageThumbRect);
  1489.     InsetRect(&pageThumbRect, 1, 1);
  1490.     ForeColor(blackColor);
  1491.     FrameRect(&pageThumbRect);
  1492.  
  1493.     // draw page string label
  1494.     TextFace(bold);
  1495.     TextFont(applFont);
  1496.     TextSize(9);
  1497.     TextMode(srcCopy);
  1498.     GetFontInfo(&theInfo);
  1499.     
  1500.     MoveTo(pageSliderRect.left, pageThumbRect.top - kPageThumbEdge - theInfo.descent);
  1501.     GetIndString(aString, kPageControlStrings, iGoToPageString);
  1502.     DrawString(aString);
  1503.     NumToString(currentValue, aString);
  1504.     DrawString(aString);
  1505.     
  1506.     // erase any trailing digits (pretty cheezy, but seems to work)
  1507.     DrawString("\p       ");
  1508.     
  1509.     // draw the proxy, or erase the proxy area if no picture to draw
  1510.     proxyHandle = (PicHandle) GetResource(kProxyType, kProxyBaseID + currentValue - 1);
  1511.     if (proxyHandle)
  1512.         {
  1513.         Rect    drawRect;
  1514.         Fixed    scaleFactor;
  1515.         
  1516.         drawRect = (**proxyHandle).picFrame;
  1517.         
  1518.         // compute aspect ratio preserving scale
  1519.         if (RectHeight(drawRect) > RectWidth(drawRect))
  1520.             scaleFactor = FixRatio(RectHeight(proxyRect), RectHeight(drawRect));
  1521.         else
  1522.             scaleFactor = FixRatio(RectWidth(proxyRect), RectWidth(drawRect));
  1523.         drawRect.bottom = drawRect.top +
  1524.                     ( FixMul( (RectHeight(drawRect) << 16), scaleFactor) >> 16);
  1525.         drawRect.right = drawRect.left +
  1526.                     ( FixMul( (RectWidth(drawRect) << 16), scaleFactor) >> 16);
  1527.         CenterRect(&drawRect, &proxyRect);
  1528.         
  1529.         // erase the area outside of the picture, but inside of the 
  1530.         // total proxy area, because some pictures will leave whitespace on the edge
  1531.         {
  1532.         RgnHandle    rgn1 = NewRgn();
  1533.         RgnHandle    rgn2 = NewRgn();
  1534.         
  1535.         RectRgn(rgn1, &proxyRect);
  1536.         RectRgn(rgn2, &drawRect);
  1537.         DiffRgn(rgn1, rgn2, rgn1);
  1538.         EraseRgn(rgn1);
  1539.         DisposeRgn(rgn1);
  1540.         DisposeRgn(rgn2);
  1541.         }
  1542.  
  1543.         // finally, we can draw and dispose of the picture
  1544.         DrawPicture(proxyHandle, &drawRect);
  1545.         ReleaseResource((Handle) proxyHandle);
  1546.         
  1547.         }
  1548.     else
  1549.         {
  1550.         EraseRect(&proxyRect);
  1551.         }
  1552.         
  1553. } // DrawPageSliderAndThumb
  1554.  
  1555. // --------------------------------------------------------------------------------------------------------------
  1556. static OSErr    DoDrawingClick(WindowRef pWindow, WindowDataPtr pData, Point clickPoint, EventRecord *pEvent)
  1557. {
  1558. #pragma unused (pEvent, pWindow)
  1559.  
  1560.     OSErr    anErr = noErr;
  1561.     Point    lastPoint = clickPoint;
  1562.     Point    currentPoint;
  1563.     Fixed    penSize;
  1564.     gxInk    newInk = GXNewInk();
  1565.     gxStyle newStyle = GXNewStyle();
  1566.     gxShape    newShape = GXNewShape(gxPolygonType);
  1567.     long    addPoly[] = {1, 1, 0, 0};
  1568.     
  1569.     // set up the style for the shape
  1570.     GXSetStylePen(newStyle, ff(10));
  1571.     
  1572.     // and the ink for the shape
  1573.     {
  1574.     gxColor    redColor;
  1575.     gxTransferMode mode;
  1576.     
  1577.     // the color
  1578.     redColor.space        = gxRGBSpace;
  1579.     redColor.profile    = nil;
  1580.     redColor.element.rgb.red    = 0xFFFF;
  1581.     redColor.element.rgb.green    = 0x0000;
  1582.     redColor.element.rgb.blue    = 0x0000;
  1583.     GXSetInkColor(newInk, &redColor);
  1584.     
  1585.     // the transfer mode
  1586.     mode.space         = gxHSVSpace;
  1587.     mode.set        = nil;
  1588.     mode.profile    = nil;
  1589.     InitColorMatrix(mode.sourceMatrix);
  1590.     InitColorMatrix(mode.deviceMatrix);
  1591.     InitColorMatrix(mode.resultMatrix);
  1592.     mode.flags        = 0;
  1593.     
  1594.     mode.component[0].mode    = gxCopyMode;
  1595.     mode.component[0].flags    = 0;
  1596.     mode.component[0].sourceMinimum    = 0;
  1597.     mode.component[0].sourceMaximum    = gxColorValue1;
  1598.     mode.component[0].deviceMinimum    = 0;
  1599.     mode.component[0].deviceMaximum    = gxColorValue1;
  1600.     mode.component[0].clampMinimum    = 0;
  1601.     mode.component[0].clampMaximum    = gxColorValue1;
  1602.     mode.component[0].operand        = 0;
  1603.  
  1604.     mode.component[1].mode    = gxCopyMode;
  1605.     mode.component[1].flags    = 0;
  1606.     mode.component[1].sourceMinimum    = 0;
  1607.     mode.component[1].sourceMaximum    = gxColorValue1;
  1608.     mode.component[1].deviceMinimum    = 0;
  1609.     mode.component[1].deviceMaximum    = gxColorValue1;
  1610.     mode.component[1].clampMinimum    = 0;
  1611.     mode.component[1].clampMaximum    = gxColorValue1;
  1612.     mode.component[1].operand        = 0;
  1613.  
  1614.     mode.component[2].mode    = gxNoMode;
  1615.     mode.component[2].flags    = 0;
  1616.     mode.component[2].sourceMinimum    = 0;
  1617.     mode.component[2].sourceMaximum    = gxColorValue1;
  1618.     mode.component[2].deviceMinimum    = 0;
  1619.     mode.component[2].deviceMaximum    = gxColorValue1;
  1620.     mode.component[2].clampMinimum    = 0;
  1621.     mode.component[2].clampMaximum    = gxColorValue1;
  1622.     mode.component[2].operand        = 0;
  1623.     GXSetInkTransfer(newInk, &mode);
  1624.     }
  1625.     
  1626.     // set the style and ink of the shape
  1627.     GXSetShapeStyle(newShape, newStyle);
  1628.     GXSetShapeInk(newShape, newInk);
  1629.     GXSetShapeFill(newShape, gxOpenFrameFill);
  1630.     
  1631.     // initialize the first point in the shape
  1632.     addPoly[2] = ff(lastPoint.h);
  1633.     addPoly[3] = ff(lastPoint.v);
  1634.     GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit);
  1635.  
  1636.     // determine the amount we require the mouse to move before adding a new point
  1637.     penSize = FixedDivide(GXGetStylePen(newStyle), ff(2));
  1638.     if (penSize < ff(1))
  1639.         penSize = ff(1);
  1640.  
  1641.     do
  1642.         {
  1643.         GetMouse(¤tPoint);
  1644.         if     (
  1645.             (ff(ABS(currentPoint.h - lastPoint.h)) > penSize) ||
  1646.             (ff(ABS(currentPoint.v - lastPoint.v)) > penSize)
  1647.             )
  1648.             {
  1649.             // add the new point to the new shape
  1650.             lastPoint = currentPoint;
  1651.             addPoly[2] = ff(lastPoint.h);
  1652.             addPoly[3] = ff(lastPoint.v);
  1653.             GXSetPolygonParts(newShape, gxSelectToEnd, 1, (gxPolygons*)addPoly, gxRemoveDuplicatePointsEdit);
  1654.             GXDrawShape(newShape);
  1655.             }
  1656.         } while (StillDown());
  1657.     
  1658.     {
  1659.     Fixed            zoomFactor = ((GXDataPtr)pData)->zoomFactor;
  1660.     Fixed            shapeScale = FixedDivide(ff(1), zoomFactor);
  1661.     gxRectangle        pageSize, paperSize;
  1662.         
  1663.     // offset the shape by the scroll bars & margins
  1664.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  1665.     GXMoveShape(newShape, 
  1666.                 ff(GetControlValue(pData->hScroll)) + FixedMultiply(paperSize.left, zoomFactor),
  1667.                 ff(GetControlValue(pData->vScroll)) + FixedMultiply(paperSize.top, zoomFactor) );
  1668.  
  1669.     // scale the shape to the current scale factor
  1670.     GXScaleShape(newShape, shapeScale, shapeScale, 0, 0 );
  1671.     GXSetShapePen(newShape, FixedMultiply(GXGetShapePen(newShape), shapeScale) );
  1672.     }
  1673.     
  1674.     // add shape to the page
  1675.     {
  1676.     gxShape        annotationShape = (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1];
  1677.     
  1678.     if (!annotationShape)
  1679.         {
  1680.         annotationShape = GXNewShape(gxPictureType);
  1681.         (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1] = annotationShape;
  1682.         }
  1683.     if (annotationShape)
  1684.         GXSetPictureParts(annotationShape, 0, 0, 1, &newShape, nil, nil, nil);
  1685.     }
  1686.  
  1687.     // all done with our copies of the shape, style, and ink    
  1688.     GXDisposeShape(newShape);
  1689.     GXDisposeStyle(newStyle);
  1690.     GXDisposeInk(newInk);
  1691.     
  1692.     // we've touched the file
  1693.     pData->changed = true;
  1694.     
  1695.     return(anErr);
  1696.     
  1697. } // DoDrawingClick
  1698.  
  1699. // --------------------------------------------------------------------------------------------------------------
  1700.  
  1701. // Handle update/activate events behind Standard File
  1702. static pascal Boolean SaveDialogFilter(DialogPtr theDialog, EventRecord *theEvent,
  1703.                                       short *itemHit, void *myDataPtr)
  1704. {
  1705.     #pragma unused(myDataPtr)
  1706.  
  1707.     if (StdFilterProc(theDialog, theEvent, itemHit))
  1708.         return true;
  1709.  
  1710.     // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby
  1711.     // drastically changing how the system handles the menu bar during our alert)
  1712.     if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ )
  1713.         {
  1714.         HandleEvent(theEvent);
  1715.         }
  1716.  
  1717.     return false;
  1718.  
  1719. } // SaveDialogFilter
  1720.  
  1721. #if GENERATINGCFM
  1722.     static RoutineDescriptor gSaveDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, SaveDialogFilter);
  1723.     static ModalFilterYDUPP gSaveDialogFilter = &gSaveDialogFilterRD;
  1724. #else
  1725.     static ModalFilterYDUPP gSaveDialogFilter = NewModalFilterYDProc(SaveDialogFilter);
  1726. #endif
  1727.  
  1728. // --------------------------------------------------------------------------------------------------------------
  1729. #define kLoadAnnotations    true
  1730. #define kSaveAnnotations    false
  1731.  
  1732. static OSErr    LoadOrSaveAnnotations(WindowDataPtr pData, Boolean load)
  1733. {
  1734.     OSErr                anErr = noErr;
  1735.     short                i;
  1736.     short                oldResFile = CurResFile();
  1737.     userSpool             block;
  1738.     
  1739.     block.spool.spoolProcedure = gHandleSpoolProc;
  1740.     
  1741.     UseResFile(((GXDataPtr)pData)->printFileRefNum);
  1742.     for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i)
  1743.         {
  1744.         gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i];
  1745.         Handle    annotationHandle;
  1746.         
  1747.         block.spool.buffer = nil;
  1748.         block.spool.bufferSize = 0;
  1749.         if (load)
  1750.             {
  1751.             // load annotation, if any
  1752.             annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1);
  1753.             if (annotationHandle)
  1754.                 {
  1755.                 block.data = annotationHandle;
  1756.                 annotation = GXUnflattenShape(&block.spool, 0, nil);
  1757.                 ReleaseResource(annotationHandle);
  1758.                 }
  1759.             else
  1760.                 {
  1761.                 annotation = nil;
  1762.                 }
  1763.             }
  1764.         else
  1765.             {
  1766.             // remove old annotation
  1767.             annotationHandle = Get1Resource(kAnnotationType, kAnnotationBaseID + i-1);
  1768.             if (annotationHandle)
  1769.                 RemoveResource(annotationHandle);
  1770.                 
  1771.             // add new annotation
  1772.             if (annotation)
  1773.                 {
  1774.                 block.spool.spoolProcedure = gHandleSpoolProc;
  1775.                 block.spool.buffer = nil;
  1776.                 block.spool.bufferSize = 0;
  1777.                 GXFlattenShape(annotation, 0, &block.spool);
  1778.                 annotationHandle = (Handle) block.data;
  1779.                 if (annotationHandle)
  1780.                     {
  1781.                     AddResource(annotationHandle, kAnnotationType, kAnnotationBaseID + i-1, "\p");
  1782.                     ReleaseResource(annotationHandle);
  1783.                     }
  1784.                 }
  1785.             }
  1786.             
  1787.         (*((GXDataPtr)pData)->pageAnnotations)[i] = annotation;
  1788.         }
  1789.     UpdateResFile(CurResFile());
  1790.     UseResFile(oldResFile);
  1791.     
  1792.     return(anErr);
  1793.     
  1794. } // LoadOrSaveAnnotations
  1795.  
  1796. // --------------------------------------------------------------------------------------------------------------
  1797. static OSErr    GXSaveAs(WindowRef pWindow, WindowDataPtr pData)
  1798. {
  1799.     OSErr                anErr = noErr;
  1800.     StandardFileReply    sfReply;
  1801.     
  1802.     // ask where and how to save this document
  1803.     {
  1804.     Str255    defaultName;
  1805.     Point    where = {-1, -1};
  1806.     
  1807.     // setup for the call
  1808.     GetWTitle(pWindow, defaultName);
  1809.     SetCursor(&qd.arrow);
  1810.     
  1811.     // find out where the user wants the file
  1812.     CustomPutFile("\p", defaultName, &sfReply, 
  1813.                 sfPutDialogID, where,
  1814.                 nil, gSaveDialogFilter, nil, nil, nil);
  1815.     
  1816.     // map the cancel button into a cancelling error
  1817.     if (!sfReply.sfGood)
  1818.         anErr = eUserCanceled;
  1819.     }
  1820.         
  1821.     // can't replace over other types    
  1822.     if (sfReply.sfReplacing)
  1823.         {
  1824.         FInfo    theInfo;
  1825.         
  1826.         FSpGetFInfo(&sfReply.sfFile, &theInfo);
  1827.         
  1828.         if ( 
  1829.             (theInfo.fdType != 'sjob') && 
  1830.             (theInfo.fdType != 'tjob') && 
  1831.             (theInfo.fdType != 'rjob') && 
  1832.             (theInfo.fdType != 'qjob') 
  1833.             )
  1834.             anErr = eDocumentWrongKind;
  1835.         }
  1836.     nrequire(anErr, StandardPutFile);
  1837.         
  1838.     GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, &sfReply.sfFile);
  1839.     anErr = GXGetJobError(pData->hPrint);
  1840.  
  1841.  
  1842.     // FALL THROUGH EXCEPTION HANDLING
  1843. StandardPutFile:
  1844.  
  1845.     // if everything went okay
  1846.     if (anErr == noErr)
  1847.         {
  1848.         // update the window title 
  1849.         SetWTitle(pWindow, sfReply.sfFile.name);
  1850.     
  1851.         // save new location
  1852.         BlockMoveData(&sfReply.sfFile, &pData->fileSpec, sizeof(FSSpec));
  1853.  
  1854.         // update the refNum
  1855.         ((GXDataPtr)pData)->printFileRefNum = CurResFile();
  1856.         
  1857.         // and read in the current page
  1858.         anErr = GetCurrentPage((GXDataPtr) pData, true);
  1859.         }
  1860.         
  1861. // Return eUserCanceled so we can avoid closing/quitting if they cancel the SF dialog
  1862. //    // don't propagate this error
  1863. //    if (anErr == eUserCanceled)
  1864. //        anErr = noErr;
  1865.  
  1866.     return anErr;
  1867.     
  1868. } // GXSaveAs
  1869.  
  1870. // --------------------------------------------------------------------------------------------------------------
  1871. // OOP INTERFACE ROUTINES
  1872. // --------------------------------------------------------------------------------------------------------------
  1873.  
  1874. static OSErr    GXCloseWindow(WindowRef pWindow, WindowDataPtr pData)
  1875. {
  1876. #pragma unused (pWindow)
  1877.  
  1878.     if (((GXDataPtr)pData)->pageAnnotations)
  1879.         {
  1880.         short    i;
  1881.         
  1882.         for (i = 0; i < ((GXDataPtr)pData)->numberOfPages; ++i)
  1883.             {
  1884.             gxShape annotation = (*((GXDataPtr)pData)->pageAnnotations)[i];
  1885.             
  1886.             if (annotation)
  1887.                 GXDisposeShape(annotation);
  1888.             }
  1889.         DisposeHandle((Handle) (((GXDataPtr)pData)->pageAnnotations) );
  1890.         ((GXDataPtr)pData)->pageAnnotations = nil;
  1891.         }
  1892.     
  1893.     if (((GXDataPtr)pData)->currentSelectionShape)
  1894.         {
  1895.         GXDisposeShape(((GXDataPtr)pData)->currentSelectionShape);
  1896.         ((GXDataPtr)pData)->currentSelectionShape = nil;
  1897.         }
  1898.                         
  1899.     if (((GXDataPtr)pData)->currentPageShape)
  1900.         {
  1901.         GXDisposeShape(((GXDataPtr)pData)->currentPageShape);
  1902.         ((GXDataPtr)pData)->currentPageShape = nil;
  1903.         }
  1904.     GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile);
  1905.  
  1906.     GXDisposeViewPort( ((GXDataPtr)pData)->parentViewPort);
  1907.     GXDisposeViewPort( ((GXDataPtr)pData)->childViewPort);
  1908.  
  1909.     return(noErr);
  1910.     
  1911. } // GXCloseWindow
  1912.  
  1913. // --------------------------------------------------------------------------------------------------------------
  1914.  
  1915. static OSErr    GXUpdateWindow(WindowRef pWindow, WindowDataPtr pData)
  1916. {
  1917.     gxGraphicsError        anErr = noErr;    
  1918.  
  1919.     // draw informational area to the left of the horizontal scroll bar
  1920.     {
  1921.     FontInfo    theInfo;
  1922.     Rect        infoArea;
  1923.     RgnHandle    oldClip = NewRgn();
  1924.     Handle        theString;
  1925.     long        theStringSize;
  1926.     
  1927.     // save old clip and clip to the label area
  1928.     GetClip(oldClip);
  1929.     infoArea.left = 0;
  1930.     infoArea.right = pData->hScrollOffset-1;
  1931.     infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom;
  1932.     infoArea.top = infoArea.bottom - kScrollBarSize;
  1933.     ClipRect(&infoArea);
  1934.         
  1935.     // draw the label
  1936.     TextFont(applFont);
  1937.     TextSize(9);
  1938.     GetFontInfo(&theInfo);
  1939.     theString = GetResource('LSTR', kLabelString);
  1940.     if (theString)
  1941.         {
  1942.         Handle    inString = NewHandle(sizeof(Str255));
  1943.         Str255    newString;
  1944.         Rect    labelArea = infoArea;
  1945.         
  1946.         // erase any old string we had there
  1947.         labelArea.right -= kZoomControlsWidth + kToolControlWidth;
  1948.         if (((GXDataPtr)pData)->numberOfPages > 1)
  1949.             labelArea.left += kPageControlsWidth;        
  1950.         EraseRect(&labelArea);
  1951.         
  1952.         // current page label
  1953.         NumToString(((GXDataPtr)pData)->currentPage, newString);
  1954.         SetHandleSize(inString, newString[0]);
  1955.         BlockMoveData(&newString[1], *inString, newString[0]);
  1956.         ReplaceText(theString, inString, "\p^0");
  1957.  
  1958.         // total page count label
  1959.         NumToString(((GXDataPtr)pData)->numberOfPages, newString);
  1960.         SetHandleSize(inString, newString[0]);
  1961.         BlockMoveData(&newString[1], *inString, newString[0]);
  1962.         ReplaceText(theString, inString, "\p^1");
  1963.  
  1964.         // scale factor label
  1965.         NumToString(FixedToInt( FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(100)) ), newString);
  1966.         SetHandleSize(inString, newString[0]);
  1967.         BlockMoveData(&newString[1], *inString, newString[0]);
  1968.         ReplaceText(theString, inString, "\p^2");
  1969.  
  1970.         // done with replace string content
  1971.         DisposeHandle(inString);
  1972.         
  1973.         // draw the label
  1974.         HLock(theString);
  1975.         theStringSize = GetHandleSize(theString);
  1976.         MoveTo(labelArea.left + ((labelArea.right - labelArea.left) >> 1) - (TextWidth(*theString, 0, theStringSize) >> 1), 
  1977.                 labelArea.top + ((labelArea.bottom - labelArea.top)>>1) + ((theInfo.ascent + theInfo.descent) >> 1) - theInfo.descent);
  1978.         DrawText(*theString, 0, theStringSize);
  1979.         ReleaseResource(theString);
  1980.         }
  1981.         
  1982.     // draw the current tool
  1983.         {
  1984.         Rect        toolArea = infoArea;
  1985.         CIconHandle    icon;
  1986.         
  1987.         toolArea.left = toolArea.right - kToolControlWidth;
  1988.         toolArea.right = toolArea.left + 32;
  1989.         toolArea.bottom = toolArea.top + 32;
  1990.         EraseRect(&toolArea);
  1991.         OffsetRect(&toolArea, -8, -8);
  1992.         
  1993.         icon = GetCIcon(kIconBase + ((GXDataPtr)pData)->contentClickMode);
  1994.         if (icon)
  1995.             {
  1996.             PlotCIconHandle(&toolArea, kAlignAbsoluteCenter, ttNone, icon);
  1997.             DisposeCIcon(icon);
  1998.             }
  1999.         }
  2000.  
  2001.     // draw the zoom controls
  2002.         {
  2003.         Rect    zoomArea = infoArea;
  2004.         zoomArea.left = zoomArea.right - kZoomControlsWidth - kToolControlWidth;
  2005.         zoomArea.right = zoomArea.left + 32;
  2006.         zoomArea.bottom = zoomArea.top + 32;
  2007.         
  2008.         PlotIconID(&zoomArea, ttNone, ttNone, kZoomControlPlain);
  2009.         }
  2010.                 
  2011.     // draw the left/right/page arrows
  2012.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2013.         {
  2014.         Rect    arrowsRect;
  2015.         
  2016.         // erase any old arrow bits, including around the edges of the icon
  2017.         // needed when the window resizes
  2018.         arrowsRect = infoArea;
  2019.         arrowsRect.bottom = arrowsRect.top + 32;
  2020.         arrowsRect.right = arrowsRect.left + 34;
  2021.         EraseRect(&arrowsRect);
  2022.         
  2023.         // then draw the new arrows
  2024.         arrowsRect.left = infoArea.left + 2;
  2025.         arrowsRect.top = infoArea.top + 2;
  2026.         arrowsRect.right = arrowsRect.left + kPageControlsWidth;
  2027.         arrowsRect.bottom = arrowsRect.top + 32;
  2028.         PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2029.         }
  2030.     
  2031.     // frame the area
  2032.     MoveTo(infoArea.left, infoArea.top);
  2033.     LineTo(infoArea.right, infoArea.top);
  2034.  
  2035.     // restore old clip value
  2036.     SetClip(oldClip);
  2037.     DisposeRgn(oldClip);
  2038.     }
  2039.  
  2040.  
  2041.     // then draw the page shape and things around it
  2042.     {
  2043.     gxRectangle            pageSize, paperSize;    
  2044.     gxShape                tempShape, pageShape;
  2045.     gxMapping            thisMapping;
  2046.  
  2047.     // clip to the content area
  2048.     paperSize.left         = ff(pData->contentRect.left);
  2049.     paperSize.top         = ff(pData->contentRect.top);
  2050.     paperSize.right     = ff(pData->contentRect.right);
  2051.     paperSize.bottom     = ff(pData->contentRect.bottom);
  2052.     tempShape = GXNewRectangle(&paperSize);
  2053.     GXSetViewPortClip(((GXDataPtr)pData)->childViewPort, tempShape);
  2054.     GXDisposeShape(tempShape);
  2055.     
  2056.     // get the paper sizes, account for zoom factor
  2057.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2058.     pageSize.left         = FixedMultiply(pageSize.left, ((GXDataPtr)pData)->zoomFactor);
  2059.     pageSize.right         = FixedMultiply(pageSize.right, ((GXDataPtr)pData)->zoomFactor);
  2060.     pageSize.top         = FixedMultiply(pageSize.top, ((GXDataPtr)pData)->zoomFactor);
  2061.     pageSize.bottom     = FixedMultiply(pageSize.bottom, ((GXDataPtr)pData)->zoomFactor);
  2062.     paperSize.left         = FixedMultiply(paperSize.left, ((GXDataPtr)pData)->zoomFactor);
  2063.     paperSize.right     = FixedMultiply(paperSize.right, ((GXDataPtr)pData)->zoomFactor);
  2064.     paperSize.top         = FixedMultiply(paperSize.top, ((GXDataPtr)pData)->zoomFactor);
  2065.     paperSize.bottom     = FixedMultiply(paperSize.bottom, ((GXDataPtr)pData)->zoomFactor);
  2066.     
  2067.     // offset by the scrolling amount    
  2068.     ResetMapping(&thisMapping);
  2069.     MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left ,
  2070.                 Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top );
  2071.  
  2072.     // make the paper shape
  2073.     tempShape = GXNewShape(gxFullType);
  2074.     GXSetTransformViewPorts(GXGetShapeTransform(tempShape), 1, & ((GXDataPtr)pData)->childViewPort);
  2075.     GXSetShapeFill(tempShape, gxEvenOddFill);
  2076.     GXSetShapeMapping(tempShape, &thisMapping);
  2077.     
  2078.     // make the page shape
  2079.     pageShape = GXNewRectangle(&pageSize);
  2080.     GXSetTransformViewPorts(GXGetShapeTransform(pageShape), 1, & ((GXDataPtr)pData)->childViewPort);
  2081.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2082.     GXSetShapeMapping(pageShape, &thisMapping);
  2083.     
  2084.     // remove the page shape from the paper shape
  2085.     GXDifferenceShape(tempShape, pageShape);
  2086.  
  2087.     // draw the paper shape, dispose of it
  2088.     SetShapeGreyColorLevel(tempShape, 0xD000);    /* Set up light gray background */
  2089.     GXDrawShape(tempShape);
  2090.     GXDisposeShape(tempShape);
  2091.     
  2092.     // draw white on the page shape
  2093.     SetShapeGreyColorLevel(pageShape, 0xFFFF);    /* Set up white page */
  2094.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2095.     GXDrawShape(pageShape);
  2096.     
  2097.     // frame the page shape
  2098.     SetShapeGreyColorLevel(pageShape, 0x8000);    /* Set up medium gray frame */
  2099.     GXSetShapeFill(pageShape, gxClosedFrameFill);
  2100.     GXDrawShape(pageShape);
  2101.     
  2102.     // draw the scroll bars and grow box now to give a nice appearence
  2103.     DrawControls(pWindow);
  2104.     DrawGrowIcon(pWindow);
  2105.  
  2106.     // draw the page data itself, clipped to the page
  2107.  
  2108.     {
  2109.     gxMapping    oldMapping, flipMapping;
  2110.     
  2111.     // get the page shape's old mapping, and make a copy to work with
  2112.     GXGetShapeMapping(((GXDataPtr)pData)->currentPageShape, &oldMapping);
  2113.  
  2114.     // run the clip through the inverse of the shape mapping to scale it properly
  2115.     GXInsetShape(pageShape, ff(1));
  2116.     ScaleMapping(&oldMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0);
  2117.     InvertMapping(&flipMapping, &oldMapping);
  2118.     GXMapShape(pageShape, &flipMapping);
  2119.     GXSetShapeFill(pageShape, gxEvenOddFill);
  2120.     GXSetShapeClip( ((GXDataPtr)pData)->currentPageShape, pageShape);
  2121.     
  2122.     // move the shape into position by offseting the viewPort
  2123.     GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping);    
  2124.     GXGetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping);    
  2125.     ScaleMapping(&thisMapping, ((GXDataPtr)pData)->zoomFactor, ((GXDataPtr)pData)->zoomFactor, 0, 0);
  2126.     MoveMapping(&thisMapping, Long2Fix(-GetControlValue(pData->hScroll)) - paperSize.left ,
  2127.                 Long2Fix(-GetControlValue(pData->vScroll)) - paperSize.top );
  2128.     GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &thisMapping);    
  2129.  
  2130.     /*
  2131.      *    Bracket the call to DrawShape with UseResFile, so that we put the
  2132.      *    document's resfile on top, allowing the translator (for QDShapes)
  2133.      *    to see our embedded fonts (if any) first.
  2134.      */
  2135.     {    short oldResFile = CurResFile();
  2136.     
  2137.         UseResFile(((GXDataPtr)pData)->printFileRefNum);
  2138.         GXDrawShape( ((GXDataPtr)pData)->currentPageShape);
  2139.         UseResFile(oldResFile);
  2140.     }
  2141.  
  2142.     
  2143.     // Draw the selection, if any
  2144.     {
  2145.     gxShape    selectionShape =  ((GXDataPtr)pData)->currentSelectionShape;
  2146.     gxShape    highlight;
  2147.     
  2148.     if (selectionShape)
  2149.         {
  2150.         
  2151.         // better be a layout shape to get hilights
  2152.         GXSetShapeType(selectionShape, gxLayoutType);
  2153.         
  2154.         // get the highlight
  2155.         highlight = GetCurrentSelectionHighlight(pData, true);
  2156.         GXDrawShape(highlight);
  2157.         GXDisposeShape(highlight);                        
  2158.         }
  2159.     }
  2160.  
  2161.     // Draw the overlay, if any
  2162.     {
  2163.     gxShape    annotationShape =  (*((GXDataPtr)pData)->pageAnnotations)[((GXDataPtr)pData)->currentPage-1];
  2164.     
  2165.     if (annotationShape)
  2166.         {
  2167.         GXSetShapeViewPorts(annotationShape, 1, &((GXDataPtr)pData)->childViewPort);
  2168.         GXDrawShape(annotationShape);
  2169.         }    
  2170.     }
  2171.  
  2172.     // restore viewPort's mapping (so we don't use it again next time)
  2173.     GXSetViewPortMapping(((GXDataPtr)pData)->childViewPort, &oldMapping);    
  2174.  
  2175.     
  2176.     }
  2177.     
  2178.     // done with the page shape
  2179.     GXDisposeShape(pageShape);
  2180.  
  2181.     DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2182.  
  2183.     GXGetGraphicsError(&anErr);
  2184.     }
  2185.     
  2186.     return(anErr);
  2187.     
  2188. } // GXUpdateWindow
  2189.  
  2190. // --------------------------------------------------------------------------------------------------------------
  2191.  
  2192. static OSErr    GXContentClick(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent)
  2193. {
  2194.     OSErr            anErr = noErr;
  2195.     Point            clickPoint = pEvent->where;
  2196.     Rect            infoArea, labelArea, toolArea;
  2197.     Rect            zoomOutRect, zoomInRect, zoomsRect;
  2198.     RgnHandle        oldClip = NewRgn();
  2199.     Boolean            somethingHit = false;
  2200.     
  2201.     // convert to local space, calculate clickable areas    
  2202.     GlobalToLocal(&clickPoint);
  2203.     infoArea.left = 0;
  2204.     infoArea.right = pData->hScrollOffset-1;
  2205.     infoArea.bottom = GetWindowPort(pWindow)->portRect.bottom;
  2206.     infoArea.top = infoArea.bottom - kScrollBarSize;
  2207.  
  2208.     // clip to the info area
  2209.     GetClip(oldClip);
  2210.     ClipRect(&infoArea);
  2211.  
  2212.     // label area
  2213.     labelArea = infoArea;
  2214.     labelArea.right -= kZoomControlsWidth + kToolControlWidth;
  2215.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2216.         labelArea.left += kPageControlsWidth;        
  2217.  
  2218.     // the tool pop up
  2219.     toolArea = infoArea;
  2220.     toolArea.left = toolArea.right - kToolControlWidth;
  2221.     
  2222.     // calculate the zoom in/out rects
  2223.     zoomInRect = infoArea;
  2224.     zoomInRect.right -= kToolControlWidth;
  2225.     zoomInRect.left = zoomInRect.right - 13;
  2226.     zoomOutRect = zoomInRect;
  2227.     OffsetRect(&zoomOutRect, -13, 0);
  2228.     zoomsRect = zoomOutRect;
  2229.     zoomsRect.bottom = zoomsRect.top + 32;
  2230.     zoomsRect.right = zoomsRect.left + 32;
  2231.  
  2232.     // deal with zoom in/out clicks
  2233.     if (TrackIn(&zoomInRect, clickPoint, &zoomsRect, kZoomControlRight, kZoomControlPlain))
  2234.         {
  2235.         somethingHit = true;
  2236.         SetZoom(pWindow, pData, FixedMultiply(((GXDataPtr)pData)->zoomFactor, ff(2)) );
  2237.         PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain);
  2238.         }
  2239.  
  2240.     if (TrackIn(&zoomOutRect, clickPoint, &zoomsRect, kZoomControlLeft, kZoomControlPlain))
  2241.         {
  2242.         somethingHit = true;
  2243.         SetZoom(pWindow, pData, FixedDivide(((GXDataPtr)pData)->zoomFactor, ff(2)) );
  2244.         PlotIconID(&zoomsRect, ttNone, ttNone, kZoomControlPlain);
  2245.         }
  2246.  
  2247.     // deal with the options pop up
  2248.     if (PtInRect(clickPoint, &labelArea))
  2249.         {
  2250.         MenuHandle    popupMenu = GetMenu(kGXPopUpMenu);
  2251.         short        selectedItem;
  2252.         TextState    textState;
  2253.         Point        popPoint;
  2254.         char        bulletString[3];
  2255.         
  2256.         // figure out where to display the pop up
  2257.         popPoint.v = labelArea.top;
  2258.         popPoint.h = labelArea.left;
  2259.         LocalToGlobal(&popPoint);
  2260.  
  2261.         somethingHit = true;
  2262.         GetIntlTokenChar(tokenCenterDot, FontToScript(applFont), bulletString);
  2263.         
  2264.         // set up menu to be small sized
  2265.         TextFont(applFont);
  2266.         TextSize(9);
  2267.         DoUseWFont(&textState, pWindow, true);
  2268.         
  2269.         // set up the menu for selected items
  2270.         SetItemMark(popupMenu, iDontShowMargins, (((GXDataPtr)pData)->dontShowMargins) ? bulletString[1] : noMark);
  2271.         {
  2272.         ZoomTableEntry *pEntry = &gZoomTable[0];
  2273.         
  2274.         while (pEntry->menuItem != 0)
  2275.             {
  2276.             SetItemMark(popupMenu, pEntry->menuItem, (((GXDataPtr)pData)->zoomFactor == pEntry->zoomFactor) ? bulletString[1] : noMark);
  2277.             pEntry++;
  2278.             }
  2279.         }
  2280.         
  2281.         // conduct the menu
  2282.         InsertMenu(popupMenu, -1);
  2283.         selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, CountMItems(popupMenu)+1) & 0xFFFF;
  2284.  
  2285.         // restore menu sizes
  2286.         DoUseWFont(&textState, nil, false);
  2287.         DeleteMenu(kGXPopUpMenu);
  2288.         
  2289.         switch (selectedItem)
  2290.             {                
  2291.             // toggle show/hide margins
  2292.             case iDontShowMargins:
  2293.                 // flip the boolean
  2294.                 ((GXDataPtr)pData)->dontShowMargins = 1 - ((GXDataPtr)pData)->dontShowMargins;
  2295.                 
  2296.                 // force update and recalc the size of window
  2297.                 InvalRect(&GetWindowPort(pWindow)->portRect);
  2298.                 AdjustScrollBars(pWindow, true, true, nil);
  2299.                 break;
  2300.  
  2301.             // scale graphics to fit the window
  2302.             case iScaleToFit:
  2303.                 {
  2304.                 gxRectangle        pageSize, paperSize;
  2305.                 Fixed            horizScale, vertScale;
  2306.                 GrafPtr            pPort = (GrafPtr)GetWindowPort(pWindow);
  2307.                 
  2308.                 GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2309.                 
  2310.                 pageSize.left = pageSize.top = 0;
  2311.                 pageSize.right = ff(pPort->portRect.right - kScrollBarSize);
  2312.                 pageSize.bottom = ff(pPort->portRect.bottom - kScrollBarSize);
  2313.                 
  2314.                 horizScale = FixedDivide(pageSize.right - pageSize.left, paperSize.right - paperSize.left);
  2315.                 vertScale = FixedDivide(pageSize.bottom - pageSize.top, paperSize.bottom - paperSize.top);
  2316.                 if (horizScale > vertScale)
  2317.                     SetZoom(pWindow, pData, vertScale);
  2318.                 else
  2319.                     SetZoom(pWindow, pData, horizScale);
  2320.                 }
  2321.                 break;
  2322.                 
  2323.             // absolute set scale cases
  2324.             default:
  2325.                 {
  2326.                 ZoomTableEntry *pEntry = &gZoomTable[0];
  2327.                 
  2328.                 while (pEntry->menuItem != 0)
  2329.                     {
  2330.                     if (selectedItem == pEntry->menuItem)
  2331.                         SetZoom(pWindow, pData, pEntry->zoomFactor);
  2332.                     pEntry++;
  2333.                     }
  2334.                 }
  2335.                 break;
  2336.             }
  2337.             
  2338.         }
  2339.         
  2340.     // deal with the tool pop up
  2341.     if (PtInRect(clickPoint, &toolArea))
  2342.         {
  2343.         MenuHandle    popupMenu = GetMenu(kGXToolMenu);
  2344.         short        selectedItem;
  2345.         Point        popPoint;
  2346.         short        i, numItems;
  2347.         
  2348.         // figure out where to display the pop up
  2349.         popPoint.v = toolArea.top;
  2350.         popPoint.h = toolArea.left;
  2351.         LocalToGlobal(&popPoint);
  2352.  
  2353.         // we've processed the mouse click
  2354.         somethingHit = true;
  2355.         
  2356.         // select our current item in the menu
  2357.         numItems = CountMItems(popupMenu);
  2358.         for (i = 1; i <= numItems; ++i)
  2359.             CheckItem(popupMenu, i, (i == ((GXDataPtr)pData)->contentClickMode) );
  2360.         
  2361.         // conduct the menu
  2362.         InsertMenu(popupMenu, -1);
  2363.         selectedItem = PopUpMenuSelect(popupMenu, popPoint.v, popPoint.h, numItems+1) & 0xFFFF;
  2364.         DeleteMenu(kGXPopUpMenu);
  2365.  
  2366.         // remember the item selected
  2367.         if (selectedItem != 0)
  2368.             ((GXDataPtr)pData)->contentClickMode = selectedItem;
  2369.             
  2370.         // invalidation the tool picture
  2371.         InvalRect(&toolArea);
  2372.         
  2373.         if (selectedItem != kSelectionTool)
  2374.             {
  2375.             // erase the old selection
  2376.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2377.     
  2378.             // clear the selection
  2379.             ((GXDataPtr)pData)->selectionRectangle.top         = 0;
  2380.             ((GXDataPtr)pData)->selectionRectangle.left        = 0;
  2381.             ((GXDataPtr)pData)->selectionRectangle.bottom    = 0;
  2382.             ((GXDataPtr)pData)->selectionRectangle.right    = 0;
  2383.     
  2384.             // draw the new selection
  2385.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2386.             }
  2387.         }
  2388.         
  2389.     // deal with clicks in page controls
  2390.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2391.         {
  2392.         Rect    leftArrowRect, rightArrowRect, arrowsRect;
  2393.         Rect    gotoPageRect;
  2394.         
  2395.         // calculate the minus one page arrow        
  2396.         leftArrowRect.top         = infoArea.top + 2;
  2397.         leftArrowRect.bottom     = leftArrowRect.top + 32;
  2398.         leftArrowRect.left         = infoArea.left + 2;
  2399.         leftArrowRect.right     = leftArrowRect.left + 11;
  2400.                 
  2401.         // calculate the go to a particular page rect        
  2402.         gotoPageRect = leftArrowRect;
  2403.         OffsetRect(&gotoPageRect, 11, 0);
  2404.         gotoPageRect.right --;
  2405.  
  2406.         // calculate the plus one page arrow        
  2407.         rightArrowRect = gotoPageRect;
  2408.         OffsetRect(&rightArrowRect, 10, 0);
  2409.         
  2410.         // calculate sum of all areas
  2411.         arrowsRect = leftArrowRect;
  2412.         arrowsRect.left     = infoArea.left + 2;
  2413.         arrowsRect.right     = arrowsRect.left + kPageControlsWidth;
  2414.                     
  2415.         if (TrackIn(&leftArrowRect, clickPoint, &arrowsRect, kPageControlLeft, kPageControlPlain))
  2416.             {
  2417.             somethingHit = true;
  2418.             if (((GXDataPtr)pData)->currentPage > 1) 
  2419.                 anErr = GXCommand(pWindow, pData, cPreviousPage, 0);
  2420.             else
  2421.                 PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2422.             }
  2423.  
  2424.         if (TrackIn(&rightArrowRect, clickPoint, &arrowsRect, kPageControlRight, kPageControlPlain))
  2425.             {
  2426.             somethingHit = true;
  2427.             if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages)
  2428.                 anErr = GXCommand(pWindow, pData, cNextPage, 0);
  2429.             else
  2430.                 PlotIconID(&arrowsRect, ttNone, ttNone, kPageControlPlain);
  2431.             }
  2432.             
  2433.         if (PtInRect(clickPoint, &gotoPageRect))
  2434.             {
  2435.             long    actualTicks;
  2436.             
  2437.             somethingHit = true;
  2438.             // pause, then check if the mouse is still down
  2439.             Delay(20, &actualTicks);
  2440.             
  2441.             // if still down, track preview window
  2442.             if (StillDown())
  2443.                 {
  2444.                 WindowRef    popWindow;
  2445.                 Rect        windowRect;
  2446.                 short        oldResFile = CurResFile();
  2447.                 
  2448.                 // put the print file on top
  2449.                 UseResFile(((GXDataPtr)pData)->printFileRefNum);
  2450.                 
  2451.                 // figure out where to place the pop up window, and then make it
  2452.                 windowRect.bottom     = arrowsRect.top - 2;
  2453.                 windowRect.left        = 2;
  2454.                 if (Count1Resources(kProxyType) > 0)
  2455.                     windowRect.top = windowRect.bottom - kPopUpWindowHeightLarge;
  2456.                 else
  2457.                     windowRect.top = windowRect.bottom - kPopUpWindowHeightSmall;
  2458.                 windowRect.right     = windowRect.left + kScrollAreaWidth + kPageControlsWidth + kZoomControlsWidth + kToolControlWidth - 4;
  2459.                     
  2460.                 LocalToGlobal(&TopLeft(windowRect));                
  2461.                 LocalToGlobal(&BotRight(windowRect));                
  2462.                 
  2463.                 popWindow = (WindowRef) NewCWindow(nil, &windowRect, "\p", true, plainDBox, (WindowPtr)-1, false, 0);
  2464.                 if (popWindow)
  2465.                     {            
  2466.                     long    oldValue = ((GXDataPtr)pData)->currentPage;
  2467.                     long    newValue = oldValue;
  2468.                     GrafPtr    popPort = (GrafPtr)GetWindowPort(popWindow);
  2469.                     
  2470.                     // draw initial location of the value
  2471.                     SetPort(popPort);
  2472.                     DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages);
  2473.                                         
  2474.                     // track the mouse, updating the value as we go
  2475.                     while (StillDown())
  2476.                         {
  2477.                         GetMouse(&clickPoint);
  2478.                         if (PtInRect(clickPoint, &popPort->portRect))
  2479.                             {
  2480.                             newValue =     clickPoint.h
  2481.                                             *
  2482.                                         ((GXDataPtr)pData)->numberOfPages
  2483.                                             /
  2484.                                         (popPort->portRect.right - popPort->portRect.left) 
  2485.                                             + 1;
  2486.                                         
  2487.                             if (oldValue != newValue)
  2488.                                 {
  2489.                                 oldValue = newValue;
  2490.                                 DrawPageSliderAndThumb(popWindow, oldValue, ((GXDataPtr)pData)->numberOfPages);
  2491.                                 }
  2492.                             }
  2493.                         }
  2494.                         
  2495.                     // and done with the pop up window, return to main window
  2496.                     DisposeWindow(popWindow);
  2497.                     SetPort((GrafPtr)GetWindowPort(pWindow));
  2498.                     
  2499.                     // if we changed the value, make it so
  2500.                     if (newValue != ((GXDataPtr)pData)->currentPage)
  2501.                         {
  2502.                         ((GXDataPtr)pData)->currentPage = newValue;
  2503.                         anErr = GetCurrentPage((GXDataPtr) pData, true);
  2504.                         InvalRect(&GetWindowPort(pWindow)->portRect);
  2505.                         }
  2506.                     }
  2507.                     
  2508.                 // restore resource chain
  2509.                 UseResFile(oldResFile);
  2510.                 }
  2511.             else
  2512.                 {
  2513.                 // otherwise, do the goto dialog box
  2514.                 anErr = GXCommand(pWindow, pData, cGotoPage, 0);
  2515.                 }
  2516.                 
  2517.             } // if (click in goto page area)
  2518.             
  2519.         } // if (> 1 page)
  2520.  
  2521.     // restore clip
  2522.     SetClip(oldClip);
  2523.     DisposeRgn(oldClip);
  2524.     
  2525.     // nothing matched so far, deal with selecting the contents
  2526.     if (!somethingHit)
  2527.         {
  2528.         Rect    selectionRect = ((GXDataPtr)pData)->selectionRectangle;
  2529.         
  2530.         
  2531.         OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll));
  2532.         if ( (gMachineInfo.haveDragMgr) && (PtInRect(clickPoint, &selectionRect)) )
  2533.             {
  2534.             ((GXDataPtr)pData)->tempDragShape = nil;
  2535.             DragAndDropArea(pWindow, pData, pEvent, 
  2536.                                 &selectionRect);
  2537.                 
  2538.                                 
  2539.             if ( ((GXDataPtr)pData)->tempDragShape )
  2540.                 GXDisposeShape( ((GXDataPtr)pData)->tempDragShape );
  2541.             }
  2542.         else
  2543.             {
  2544.             LongRect        docRect;
  2545.             Rect            contentRect;
  2546.             
  2547.             contentRect = GetWindowPort(pWindow)->portRect;
  2548.             contentRect.right -= kScrollBarSize;
  2549.             contentRect.bottom -= kScrollBarSize;
  2550.             
  2551.             if (PtInRect(clickPoint, &contentRect))
  2552.                 {
  2553.                 switch (((GXDataPtr)pData)->contentClickMode)
  2554.                     {
  2555.                     case kSelectionTool:
  2556.                         GXGetDocumentRect(pWindow, pData, &docRect, false);
  2557.                         contentRect.top     = docRect.top;
  2558.                         contentRect.left     = docRect.left;
  2559.                         contentRect.bottom     = docRect.bottom;
  2560.                         contentRect.right     = docRect.right;
  2561.                         
  2562.                         anErr = SelectContents(pWindow, pData, pEvent, 
  2563.                                             &((GXDataPtr)pData)->selectionRectangle, &contentRect, 
  2564.                                             &((GXDataPtr)pData)->patternPhase);
  2565.                 
  2566.                         // existing text selection? clear the highlight
  2567.                         if (((GXDataPtr)pData)->currentSelectionShape)
  2568.                             {
  2569.                             InvalRect(&GetWindowPort(pWindow)->portRect);
  2570.                             
  2571.                             ClearCurrentSelection((GXDataPtr)pData);
  2572.                             }
  2573.                         break;
  2574.  
  2575.                     case kRedMarkerTool:
  2576.                         DoDrawingClick(pWindow, pData, clickPoint, pEvent);
  2577.                         break;
  2578.                         
  2579.                     } // switch (mode)
  2580.                     
  2581.                 } // click in content rect
  2582.             }
  2583.         }
  2584.         
  2585.     return(anErr);
  2586.         
  2587. } // GXContentClick
  2588.  
  2589. // --------------------------------------------------------------------------------------------------------------
  2590.  
  2591. static OSErr    GXAdjustMenus(WindowRef pWindow, WindowDataPtr pData)
  2592. {
  2593. #pragma unused (pWindow)
  2594.  
  2595.     OSErr anErr = noErr;
  2596.     
  2597.     EnableCommand(cSaveAs);
  2598.  
  2599.     if (((GXDataPtr)pData)->numberOfPages > 1)
  2600.         {
  2601.         if (((GXDataPtr)pData)->currentPage < ((GXDataPtr)pData)->numberOfPages)
  2602.             EnableCommand(cNextPage);
  2603.             
  2604.         if (((GXDataPtr)pData)->currentPage > 1)
  2605.             EnableCommand(cPreviousPage);
  2606.         
  2607.         EnableCommand(cGotoPage);
  2608.         }
  2609.         
  2610.     if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle) )
  2611.         EnableCommand(cCopy);
  2612.  
  2613.     {
  2614.     LongRect        docRect;
  2615.     Rect            shortDocRect;
  2616.     
  2617.     // find out the size of the document            
  2618.     GXGetDocumentRect(pWindow, pData, &docRect, false);
  2619.     LongRectToRect(&docRect, &shortDocRect);
  2620.     if     (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle))
  2621.         ChangeCommandName(cSelectAll, kMiscStrings, iSelectNoneCommand);
  2622.     else
  2623.         ChangeCommandName(cSelectAll, kMiscStrings, iSelectAllCommand);
  2624.     }
  2625.     EnableCommand(cSelectAll);
  2626.     
  2627.     EnableCommand(cFind);
  2628.     if (gFindString[0] != 0)
  2629.         EnableCommand(cFindAgain);
  2630.     
  2631.     return(anErr);
  2632.     
  2633. } // GXAdjustMenus
  2634.  
  2635. // --------------------------------------------------------------------------------------------------------------
  2636.  
  2637. OSErr    GXCommand(WindowRef pWindow, WindowDataPtr pData, short commandID, long menuResult)
  2638. {
  2639. #pragma unused (menuResult)
  2640.  
  2641.     OSErr    anErr = noErr;
  2642.         
  2643.     switch (commandID)
  2644.         {
  2645.         case cSave:
  2646.             GXSavePrintFile(((GXDataPtr)pData)->thePrintFile, nil);
  2647.             anErr = GXGetJobError(pData->hPrint);
  2648.             if (anErr == noErr)
  2649.                 anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations);
  2650.                 
  2651.             // if everything went okay, then clear the changed bit
  2652.             if (anErr == noErr)
  2653.                 pData->changed = false;
  2654.             break;
  2655.             
  2656.         case cSaveAs:
  2657.             anErr = GXSaveAs(pWindow, pData);
  2658.             if (anErr == noErr)
  2659.                 anErr = LoadOrSaveAnnotations(pData, kSaveAnnotations);
  2660.  
  2661.             // if everything went okay, then clear the changed bit
  2662.             if (anErr == noErr)
  2663.                 pData->changed = false;
  2664.             break;
  2665.             
  2666.         case cFind:
  2667.             if (ConductFindOrReplaceDialog(kFindWindowID) == cancel)    
  2668.                 break;
  2669.             
  2670.             // start search at top of page
  2671.             ((GXDataPtr)pData)->currentShapeIndex = 0;
  2672.             
  2673.         // fall through from find
  2674.         case cFindAgain:
  2675.             {
  2676.             Boolean    isBackwards = ((gEvent.modifiers & shiftKey) != 0);
  2677.             
  2678.             SetWatchCursor();
  2679.  
  2680.             if (!PerformNextFind(pWindow, pData, gFindString, gCaseSensitive, isBackwards, gWrapAround))
  2681.                 SysBeep(1);
  2682.             else
  2683.                 ScrollFoundShapeIntoView(pWindow, pData);
  2684.                 
  2685.             SetCursor(&qd.arrow);
  2686.             }
  2687.             break;
  2688.  
  2689.         case cCopy:
  2690.             {
  2691.             gxShape            cullShape = GetSelectedShape(pData);
  2692.  
  2693.             if (cullShape)
  2694.                 {
  2695.                 // done with the shape now
  2696.                 ShapeToScrap(cullShape);
  2697.                 GXDisposeShape(cullShape);
  2698.                 }
  2699.             }
  2700.             break;
  2701.         
  2702.         case cSelectAll:
  2703.             {
  2704.             LongRect        docRect;
  2705.             Rect            shortDocRect;
  2706.             
  2707.             // find out the size of the document            
  2708.             GXGetDocumentRect(pWindow, pData, &docRect, false);
  2709.  
  2710.             // erase the old selection
  2711.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2712.             
  2713.             LongRectToRect(&docRect, &shortDocRect);
  2714.             if     (EqualRect(&shortDocRect, &((GXDataPtr)pData)->selectionRectangle))
  2715.                 {
  2716.                 ((GXDataPtr)pData)->selectionRectangle.top         = 0;
  2717.                 ((GXDataPtr)pData)->selectionRectangle.left        = 0;
  2718.                 ((GXDataPtr)pData)->selectionRectangle.bottom    = 0;
  2719.                 ((GXDataPtr)pData)->selectionRectangle.right    = 0;
  2720.                 }
  2721.             else
  2722.                 {
  2723.                 ((GXDataPtr)pData)->selectionRectangle.top         = docRect.top;
  2724.                 ((GXDataPtr)pData)->selectionRectangle.left        = docRect.left;
  2725.                 ((GXDataPtr)pData)->selectionRectangle.bottom    = docRect.bottom;
  2726.                 ((GXDataPtr)pData)->selectionRectangle.right    = docRect.right;
  2727.                 }
  2728.  
  2729.             // draw the new selection
  2730.             DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2731.             }
  2732.             break;
  2733.  
  2734.         case cPageSetup:
  2735.             DoPageSetup(pWindow);
  2736.             anErr = GetCurrentPage((GXDataPtr) pData, false);
  2737.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2738.             anErr = eActionAlreadyHandled;
  2739.             break;
  2740.             
  2741.         case cNextPage:
  2742.             ((GXDataPtr)pData)->currentPage++;
  2743.             anErr = GetCurrentPage((GXDataPtr) pData, true);
  2744.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2745.             if (anErr == noErr)
  2746.                 anErr = eActionAlreadyHandled;
  2747.             break;
  2748.         
  2749.         case cPreviousPage:
  2750.             ((GXDataPtr)pData)->currentPage--;
  2751.             anErr = GetCurrentPage((GXDataPtr) pData, true);
  2752.             InvalRect(&GetWindowPort(pWindow)->portRect);
  2753.             if (anErr == noErr)
  2754.                 anErr = eActionAlreadyHandled;
  2755.             break;
  2756.         
  2757.         case cGotoPage:
  2758.             switch (menuResult)
  2759.                 {
  2760.                 case cGotoFirst:
  2761.                     ((GXDataPtr)pData)->currentPage = 1;
  2762.                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2763.                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2764.                     break;
  2765.  
  2766.                 case cGotoLast:
  2767.                     ((GXDataPtr)pData)->currentPage = ((GXDataPtr)pData)->numberOfPages;
  2768.                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2769.                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2770.                     break;
  2771.                     
  2772.                 default:
  2773.                     {
  2774.                     DialogRef    dPtr;
  2775.                     short        hit;
  2776.                     
  2777.                     dPtr = GetNewDialog(kGotoPageDialogID, nil, (WindowRef)-1);
  2778.                     if (dPtr)
  2779.                         {
  2780.                         short    theType;
  2781.                         Handle    theHandle;
  2782.                         Rect    theRect;
  2783.                         Str255    theString;
  2784.                         
  2785.                         GetDialogItem(dPtr, 4, &theType, &theHandle, &theRect);
  2786.                         NumToString(((GXDataPtr)pData)->currentPage, theString);
  2787.                         SetDialogItemText(theHandle, theString);
  2788.                         SelectDialogItemText(dPtr, 4, 0, 32767);
  2789.  
  2790.                         NumToString(((GXDataPtr)pData)->numberOfPages, theString);
  2791.                         ParamText(theString, "\p", "\p", "\p");
  2792.                         
  2793.                         SetDialogDefaultItem(dPtr, ok);
  2794.                         SetDialogCancelItem(dPtr, cancel);
  2795.                         BeginMovableModal();
  2796.                         
  2797.                         do
  2798.                             {
  2799.                             MovableModalDialog(nil, &hit);
  2800.                             
  2801.                             if (hit == ok)
  2802.                                 {
  2803.                                 long    tempLong;
  2804.                                 
  2805.                                 // convert to a page number, find and report errors
  2806.                                 GetDialogItemText(theHandle, theString);
  2807.                                 StringToNum(theString, &tempLong);
  2808.                                 if (tempLong < 1) 
  2809.                                     {
  2810.                                     SysBeep(1);
  2811.                                     tempLong = 1;
  2812.                                     hit = 0;
  2813.                                     }
  2814.                                 if (tempLong > ((GXDataPtr)pData)->numberOfPages)
  2815.                                     {
  2816.                                     tempLong = ((GXDataPtr)pData)->numberOfPages;
  2817.                                     hit = 0;
  2818.                                     }
  2819.                                     
  2820.                                 // if we have an error, we try again, otherwise we go to the page
  2821.                                 if (hit == 0)
  2822.                                     {
  2823.                                     SysBeep(1);
  2824.                                     NumToString(tempLong, theString);
  2825.                                     SetDialogItemText(theHandle, theString);
  2826.                                     SelectDialogItemText(dPtr, 4, 0, 32767);
  2827.                                     }
  2828.                                 else
  2829.                                     {
  2830.                                     ((GXDataPtr)pData)->currentPage = tempLong;
  2831.                                     anErr = GetCurrentPage((GXDataPtr) pData, true);
  2832.                                     InvalRect(&GetWindowPort(pWindow)->portRect);
  2833.                                     }
  2834.                                 }
  2835.                             } while ((hit != ok) && (hit != cancel));
  2836.                             
  2837.                         DisposeDialog(dPtr);
  2838.                         EndMovableModal();
  2839.                         }
  2840.                         
  2841.                     }
  2842.                     break;
  2843.                     
  2844.                 }
  2845.             if (anErr == noErr)
  2846.                 anErr = eActionAlreadyHandled;
  2847.             break;
  2848.         
  2849.         }
  2850.     
  2851.     return(anErr);
  2852.     
  2853. } // GXCommand
  2854.  
  2855. // --------------------------------------------------------------------------------------------------------------
  2856. static OSErr    GXFilePrintPage(WindowRef pWindow, WindowDataPtr pData,
  2857.                     Rect * pageRect, long *pageNum)
  2858. {
  2859. #pragma unused (pWindow, pageRect)
  2860.  
  2861.     OSErr        anErr = noErr;
  2862.     gxShape     thisShape;
  2863.     gxFormat     thisFormat;
  2864.     
  2865.     GXReadPrintFilePage(((GXDataPtr)pData)->thePrintFile, *pageNum, 0, nil, &thisFormat, &thisShape);
  2866.     anErr = GXGetJobError(pData->hPrint);
  2867.     nrequire(anErr, ReadPrintFilePage);
  2868.  
  2869.     GXPrintPage(pData->hPrint, *pageNum, thisFormat, thisShape);
  2870.     anErr = GXGetJobError(pData->hPrint);
  2871.     nrequire(anErr, PrintPage);
  2872.  
  2873.     GXDisposeFormat(thisFormat);
  2874.     GXDisposeShape(thisShape);
  2875.  
  2876. // FALL THROUGH EXCEPTION HANDLING
  2877. PrintPage:
  2878. ReadPrintFilePage:
  2879.     // tell it to stop printing when we reach the end
  2880.     if (*pageNum >= ((GXDataPtr)pData)->numberOfPages)
  2881.         *pageNum = -1;
  2882.     
  2883.     return(anErr);
  2884.     
  2885. } // GXFilePrintPage
  2886.  
  2887. // --------------------------------------------------------------------------------------------------------------
  2888.  
  2889. OSErr    GXGetDocumentRect(WindowRef pWindow, WindowDataPtr pData, 
  2890.             LongRect * documentRectangle, Boolean forGrow)
  2891. {
  2892. #pragma unused (pWindow, forGrow)
  2893.  
  2894.     gxRectangle        pageSize, paperSize;
  2895.     
  2896.     GetCurrentPageAndPaper(pData, &pageSize, &paperSize);
  2897.  
  2898.     documentRectangle->left = 0;
  2899.     documentRectangle->top = 0;
  2900.     documentRectangle->bottom = FixedMultiply(paperSize.bottom - paperSize.top, ((GXDataPtr)pData)->zoomFactor) >> 16;
  2901.     documentRectangle->right = FixedMultiply(paperSize.right - paperSize.left, ((GXDataPtr)pData)->zoomFactor) >> 16;
  2902.         
  2903.     return(noErr);
  2904.     
  2905. } // GXGetDocumentRect
  2906.  
  2907. // --------------------------------------------------------------------------------------------------------------
  2908.  
  2909. static long GXCalculateIdleTime(WindowRef pWindow, WindowDataPtr pData)
  2910. {
  2911. #pragma unused (pWindow)
  2912.  
  2913.     if (!EmptyRect( &((GXDataPtr)pData)->selectionRectangle))
  2914.         return(0);
  2915.     else
  2916.         return(kMaxWaitTime);
  2917.         
  2918. } // GXCalculateIdleTime
  2919.  
  2920. // --------------------------------------------------------------------------------------------------------------
  2921.  
  2922. static Boolean    GXFilterEvent(WindowRef pWindow, WindowDataPtr pData, EventRecord *pEvent)
  2923. {
  2924.     if     (
  2925.         (!gMachineInfo.amInBackground) &&
  2926.         (pEvent->what == nullEvent) &&
  2927.         (pWindow == FrontWindow()) &&
  2928.         (EmptyRgn( ((WindowPeek)pWindow)->updateRgn)) &&
  2929.         (MOVESELECTION(pEvent->when) )
  2930.         )
  2931.         {
  2932.         // erase the old
  2933.         DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, false);
  2934.         
  2935.         // draw the new, moving onto the next pattern
  2936.         DrawSelection(pData, &((GXDataPtr)pData)->selectionRectangle, &((GXDataPtr)pData)->patternPhase, true);
  2937.         }
  2938.         
  2939.     return(false);
  2940.     
  2941. } // GXFilterEvent
  2942.  
  2943. // --------------------------------------------------------------------------------------------------------------
  2944.  
  2945. static OSErr    GXDragAddFlavors(WindowRef pWindow, WindowDataPtr pData, DragReference theDragRef)
  2946. {
  2947. #pragma unused (pWindow)
  2948.  
  2949.     OSErr    anErr = noErr;
  2950.     
  2951.     SetDragSendProc(theDragRef, gGXSendDataProc, nil);
  2952.     AddDragItemFlavor(theDragRef, (unsigned long)pData, 'qdgx', nil, 0, 0);
  2953.     AddDragItemFlavor(theDragRef, (unsigned long)pData, 'PICT', nil, 0, 0);
  2954.     
  2955.     return(anErr);
  2956.     
  2957. } // GXDragAddFlavors
  2958.  
  2959. // --------------------------------------------------------------------------------------------------------------
  2960.  
  2961. static OSErr    GXAdjustCursor(WindowRef pWindow, WindowDataPtr pData, Point * localMouse, Rect * globalRect)
  2962. {
  2963. #pragma unused (pWindow, globalRect)
  2964.  
  2965.     OSErr            anErr = noErr;
  2966.     Handle        theCursor;
  2967.     Rect            selectionRect = ((GXDataPtr)pData)->selectionRectangle;
  2968.     
  2969.     OffsetRect(&selectionRect, -GetControlValue(pData->hScroll), -GetControlValue(pData->vScroll));
  2970.     if (!PtInRect(*localMouse, &selectionRect) )
  2971.         {
  2972.         short    cursorID;
  2973.         Boolean    colorCursor;
  2974.         
  2975.         cursorID = ((GXDataPtr)pData)->contentClickMode;
  2976.         if (cursorID == kSelectionTool)
  2977.             {
  2978.             colorCursor = false;
  2979.             cursorID = crossCursor;
  2980.             }
  2981.         else
  2982.             {
  2983.             colorCursor = true;
  2984.             cursorID += kIconBase;
  2985.             }
  2986.             
  2987.         if (colorCursor)
  2988.             theCursor = (Handle)GetCCursor(cursorID);
  2989.         else
  2990.             theCursor = (Handle)GetCursor(cursorID);
  2991.         if (theCursor)
  2992.             {
  2993.             if (colorCursor)
  2994.                 {
  2995.                 SetCCursor((CCrsrHandle)theCursor);
  2996.                 DisposeCCursor((CCrsrHandle)theCursor);
  2997.                 }
  2998.             else
  2999.                 {
  3000.                 char    oldState;
  3001.                 
  3002.                 oldState = HGetState(theCursor);
  3003.                 HLock((Handle) theCursor);
  3004.                 SetCursor(*(CursHandle)theCursor);
  3005.                 HSetState(theCursor, oldState);
  3006.                 }
  3007.             anErr = eActionAlreadyHandled;
  3008.             }
  3009.         }
  3010.     return(anErr);
  3011.     
  3012. } // GXAdjustCursor
  3013.  
  3014. // --------------------------------------------------------------------------------------------------------------
  3015.  
  3016. static OSErr    GXMakeWindow(WindowRef pWindow, WindowDataPtr pData)
  3017. {
  3018.     OSErr                anErr = noErr;
  3019.     
  3020.     pData->pCloseWindow         = (CloseWindowProc)            GXCloseWindow;
  3021.     pData->pAdjustMenus         = (AdjustMenusProc)            GXAdjustMenus;
  3022.     pData->pCommand                = (CommandProc)                GXCommand;
  3023.     pData->pUpdateWindow         = (UpdateWindowProc)        GXUpdateWindow;
  3024.     pData->pContentClick         = (ContentClickProc)        GXContentClick;
  3025.     pData->pGetDocumentRect     = (GetDocumentRectProc)        GXGetDocumentRect;
  3026.     pData->pPrintPage             = (PrintPageProc)            GXFilePrintPage;
  3027.     pData->pFilterEvent             = (FilterEventProc)            GXFilterEvent;
  3028.     pData->pCalculateIdleTime    = (CalculateIdleTimeProc)    GXCalculateIdleTime;
  3029.     pData->pAdjustCursor        = (AdjustCursorProc)        GXAdjustCursor;
  3030.     pData->pDragAddFlavors        = (DragAddFlavorsProc)        GXDragAddFlavors;
  3031.     
  3032.     pData->documentOutputsGX    = true;
  3033.     pData->hasGrow                = true;
  3034.     pData->minHSize                = kMinGXDocSize + kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth;
  3035.     pData->hScrollAmount        = 10;
  3036.     pData->vScrollAmount        = 10;
  3037.     pData->hScrollOffset        = kScrollAreaWidth + kZoomControlsWidth + kToolControlWidth;
  3038.     
  3039.     // default the job info, which we need to have
  3040.     anErr = DoDefault(pData);
  3041.     nrequire(anErr, DoDefault);
  3042.  
  3043.     ((GXDataPtr)pData)->thePrintFile = GXOpenPrintFile(pData->hPrint, &pData->fileSpec, fsRdWrPerm);
  3044.     anErr = GXGetJobError(pData->hPrint);
  3045.     nrequire(anErr, OpenPrintFile);
  3046.  
  3047.     /*
  3048.      *    The assumption here is that the GXOpenPrintFile leaves the resfile on top.
  3049.      *    We need this refnum so that any resource handles the translator gets will
  3050.      *    match those that GXOpenPrintFile used for calls to GXNewFont.  See the call
  3051.      *    to GXDrawShape in GXUpdateWindow
  3052.      */
  3053.     ((GXDataPtr)pData)->printFileRefNum = CurResFile();
  3054.  
  3055.     // close down other paths to the file -- because we don't need them
  3056.     if (pData->resRefNum != -1)
  3057.         {
  3058.         CloseResFile(pData->resRefNum);
  3059.         pData->resRefNum = -1;
  3060.         }
  3061.     if (pData->dataRefNum != -1)
  3062.         {
  3063.         FSClose(pData->dataRefNum);
  3064.         pData->dataRefNum = -1;
  3065.         }
  3066.         
  3067.     // default to normal printing -- so if the user prints, we go to normal mode at first
  3068.     {
  3069.     Collection    jobCollection = GXGetJobCollection(pData->hPrint);
  3070.     gxJobInfo    theInfo;
  3071.     long        theSize = sizeof(theInfo);
  3072.     
  3073.     if (GetCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, &theSize, &theInfo) == noErr)
  3074.         {
  3075.         theInfo.priority = gxPrintJobASAP;
  3076.         AddCollectionItem(jobCollection, gxJobTag, gxPrintingTagID, theSize, &theInfo);
  3077.         }
  3078.     
  3079.     }
  3080.     
  3081.     // by default we have no pages
  3082.     ((GXDataPtr)pData)->numberOfPages        = GXCountPrintFilePages(((GXDataPtr)pData)->thePrintFile);
  3083.     ((GXDataPtr)pData)->currentPage            = 1;
  3084.     ((GXDataPtr)pData)->zoomFactor            = ff(1);
  3085.     ((GXDataPtr)pData)->contentClickMode    = kSelectionTool;
  3086.     anErr = GXGetJobError(pData->hPrint);
  3087.     if ( (anErr == noErr) && (((GXDataPtr)pData)->numberOfPages == 0) )
  3088.         anErr = eDocumentContainsNoPages;
  3089.     nrequire(anErr, GXCountPrintFilePages);
  3090.     
  3091.     if (((GXDataPtr)pData)->numberOfPages > 1)
  3092.         pData->hScrollOffset += kPageControlsWidth;
  3093.         
  3094.     ((GXDataPtr)pData)->pageAnnotations = (gxShape**) NewHandleClear( (((GXDataPtr)pData)->numberOfPages * sizeof(gxShape)) );
  3095.     anErr = MemError();
  3096.     if (anErr == noErr)
  3097.         anErr = LoadOrSaveAnnotations(pData, kLoadAnnotations);
  3098.     nrequire(anErr, FailedToAllocateAnnotation);
  3099.     
  3100.     // set up so we can draw inside of this window
  3101.     ((GXDataPtr)pData)->parentViewPort = GXNewWindowViewPort((WindowPtr)pWindow);
  3102.     ((GXDataPtr)pData)->childViewPort = GXNewViewPort(gxScreenViewDevices);
  3103.     GXSetViewPortParent(((GXDataPtr)pData)->childViewPort, ((GXDataPtr)pData)->parentViewPort);
  3104.     GXSetViewPortAttributes(((GXDataPtr)pData)->childViewPort, gxAlwaysGridPort);
  3105.     GXSetViewPortDither(((GXDataPtr)pData)->childViewPort, 4);
  3106.     
  3107.     // fetch the current page
  3108.     anErr = GetCurrentPage((GXDataPtr) pData, true);
  3109.     nrequire(anErr, GetCurrentPage);
  3110.     
  3111.     // if this document contains PostScript do a warning
  3112.     {
  3113.     gxTranslatedDocumentInfo theInfo;
  3114.     long theSize = sizeof(theInfo);
  3115.     
  3116.     if     (
  3117.         (GetCollectionItem(GXGetJobCollection(pData->hPrint),
  3118.                             gxTranslatedDocumentTag,
  3119.                             gxPrintingTagID,
  3120.                             &theSize,
  3121.                             &theInfo
  3122.                             ) == noErr) &&
  3123.         (theInfo.translatorInfo & gxContainsPostScript)
  3124.         )
  3125.         ConductErrorDialog(eDocumentContainsPS, cOpen, ok);
  3126.     }
  3127.     
  3128.     return(anErr);
  3129.     
  3130. // EXCEPTION HANDLING
  3131. GetCurrentPage:
  3132. FailedToAllocateAnnotation:
  3133. GXCountPrintFilePages:
  3134.     GXClosePrintFile( ((GXDataPtr)pData)->thePrintFile);
  3135.     
  3136. OpenPrintFile:
  3137.     GXDisposeJob(pData->hPrint);
  3138.         
  3139. DoDefault:
  3140.     return(anErr);
  3141.     
  3142. } // GXMakeWindow
  3143.  
  3144.  
  3145. // --------------------------------------------------------------------------------------------------------------
  3146.  
  3147. OSErr    GXPreflightWindow(PreflightPtr pPreflightData)
  3148. {    
  3149.     pPreflightData->continueWithOpen     = true;
  3150.     pPreflightData->wantVScroll            = true;
  3151.     pPreflightData->wantHScroll            = true;
  3152.     pPreflightData->doZoom                = true;
  3153.     pPreflightData->makeProcPtr         = GXMakeWindow;
  3154.     pPreflightData->storageSize         = sizeof(GXDataRecord);
  3155.     
  3156.     return(noErr);
  3157.     
  3158. } // GXPreflightWindow
  3159.  
  3160. // --------------------------------------------------------------------------------------------------------------
  3161.  
  3162. void GXGetFileTypes(OSType * pFileTypes, OSType * pDocumentTypes, short * numTypes)
  3163. {
  3164.     if (gMachineInfo.haveGX)
  3165.         {
  3166.         pFileTypes[*numTypes]         = 'sjob';
  3167.         pDocumentTypes[*numTypes]     = kGXWindow;
  3168.         (*numTypes)++;
  3169.  
  3170.         pFileTypes[*numTypes]         = 'tjob';
  3171.         pDocumentTypes[*numTypes]     = kGXWindow;
  3172.         (*numTypes)++;
  3173.  
  3174.         pFileTypes[*numTypes]         = 'rjob';
  3175.         pDocumentTypes[*numTypes]     = kGXWindow;
  3176.         (*numTypes)++;
  3177.  
  3178.         pFileTypes[*numTypes]         = 'qjob';
  3179.         pDocumentTypes[*numTypes]     = kGXWindow;
  3180.         (*numTypes)++;
  3181.         }
  3182.         
  3183. } // GXGetFileTypes
  3184.